async / await
Keywords in C# that enable asynchronous programming, allowing non-blocking execution of long-running operations without explicit callbacks.
public async Task MyAsyncMethod() { await SomeOtherAsyncCall(); }This static page keeps the syntax and examples indexed for search, while the coding app handles interactive exploration and saved references.
What it does
Overview
Keywords in C# that enable asynchronous programming, allowing non-blocking execution of long-running operations without explicit callbacks.
The `async` and `await` keywords are fundamental to modern asynchronous programming in C#. The `async` modifier marks a method as asynchronous, indicating that it can contain `await` expressions. An `async` method typically returns a `Task` for methods that don't return a value, or `Task<TResult>` for methods that return a value of type `TResult`. The `await` operator can only be used within an `async` method and is applied to an awaitable expression, typically a `Task`. When `await` is encountered, if the awaited task is not yet complete, the current method is suspended, and control is returned to the caller. This allows the calling thread (e.g., UI thread) to remain responsive. Once the awaited task completes, the remainder of the `async` method resumes execution, often on a different thread pool thread or the original synchronization context. This non-blocking nature is crucial for UI applications to prevent freezing and for server applications to scale efficiently by not tying up threads. Time complexity is not directly applicable to `async`/`await` themselves, but rather to the underlying asynchronous operations. Edge cases include `async void` (generally discouraged except for event handlers due to error handling difficulties), and deadlocks when mixing `async`/`await` with blocking calls (`.Result`, `.Wait()`) without proper `ConfigureAwait(false)`. Best practices include using `async`/`await` for I/O-bound operations, avoiding `async void` where possible, and understanding `ConfigureAwait` to prevent deadlocks in library code.
Quick reference
Syntax
public async Task MyAsyncMethod() { await SomeOtherAsyncCall(); }
See it in practice
Examples
Basic async method with Task.Delay
using System.Threading.Tasks;
using System;
public class AsyncExample
{
public static async Task SimulateWork()
{
Console.WriteLine("Starting work...");
await Task.Delay(2000); // Simulate an I/O-bound operation
Console.WriteLine("Work finished!");
}
public static async Task Main()
{
Task workTask = SimulateWork();
Console.WriteLine("Main thread continues while work is ongoing.");
await workTask;
Console.WriteLine("Main thread finished waiting.");
}
}Starting work... Main thread continues while work is ongoing. Work finished! Main thread finished waiting.
Demonstrates how `await Task.Delay` pauses the `SimulateWork` method without blocking the `Main` thread, allowing it to continue execution.
Async method returning a value
using System.Threading.Tasks;
using System;
public class AsyncValueExample
{
public static async Task<int> GetLengthAsync(string text)
{
await Task.Delay(500);
return text.Length;
}
public static async Task Main()
{
string data = "Asynchronous Programming";
Console.WriteLine("Requesting length...");
int length = await GetLengthAsync(data);
Console.WriteLine($"Length of '{data}' is {length}.");
}
}Requesting length... Length of 'Asynchronous Programming' is 24.
An `async` method can return `Task<T>` to provide a result after its asynchronous operation completes.
Handling exceptions in async methods
using System.Threading.Tasks;
using System;
public class AsyncErrorExample
{
public static async Task FailAsync()
{
await Task.Delay(100);
throw new InvalidOperationException("Something went wrong asynchronously!");
}
public static async Task Main()
{
try
{
await FailAsync();
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"Caught exception: {ex.Message}");
}
}
}Caught exception: Something went wrong asynchronously!
Exceptions thrown in `async` methods are wrapped in the returned `Task` and can be caught using a standard `try-catch` block when `await`ing the task.
Debug faster
Common Errors
Deadlock
Cause: Blocking on an `async` method's result using `.Result` or `.Wait()` in a context that requires a synchronization context (e.g., UI thread, ASP.NET request context), while the `async` method tries to resume on that same context.
Fix: Use `await` consistently throughout your `async` call chain. If you must block, consider using `ConfigureAwait(false)` in library code to prevent capturing the context, or ensure you're in a context where blocking is safe (e.g., a console app's `Main` method using `Task.Run().Wait()`).
public async Task<string> GetDataAsync() { await Task.Delay(100); return "Data"; }
// In a UI event handler or ASP.NET controller:
// string data = GetDataAsync().Result; // Potential deadlockRuntime support
Compatibility
Source: Microsoft Learn
Common questions
Frequently Asked Questions
Keywords in C# that enable asynchronous programming, allowing non-blocking execution of long-running operations without explicit callbacks.
Deadlock: Use `await` consistently throughout your `async` call chain. If you must block, consider using `ConfigureAwait(false)` in library code to prevent capturing the context, or ensure you're in a context where blocking is safe (e.g., a console app's `Main` method using `Task.Run().Wait()`).