Syntax
async Task MethodName() {\n await SomeAsyncOperation();\n}Examples
A Basic Async Method
Marking a method async and awaiting a delay.
async Task GreetAfterDelayAsync()
{
Console.WriteLine("Starting...");
await Task.Delay(1000); // pauses here without blocking the thread
Console.WriteLine("One second later!");
}
await GreetAfterDelayAsync();Async Methods That Return a Value
async Task<T> is the async equivalent of a method that returns T.
async Task<int> GetNumberAsync()
{
await Task.Delay(500);
return 42;
}
int result = await GetNumberAsync();
Console.WriteLine(result); // 42Why Async Matters: Not Blocking the Thread
Comparing a blocking synchronous wait to a non-blocking async one.
// Synchronous: blocks the calling thread entirely for 2 seconds
void BlockingWait()
{
Thread.Sleep(2000);
Console.WriteLine("Done (blocked the thread the whole time)");
}
// Asynchronous: frees the thread to do other work while waiting
async Task NonBlockingWaitAsync()
{
await Task.Delay(2000);
Console.WriteLine("Done (thread was free to do other work)");
}
await NonBlockingWaitAsync();Awaiting Multiple Steps in Sequence
await pauses at each step, but the code still reads top-to-bottom like synchronous code.
async Task<string> FetchDataAsync()
{
Console.WriteLine("Step 1: connecting...");
await Task.Delay(300);
Console.WriteLine("Step 2: downloading...");
await Task.Delay(300);
return "data loaded";
}
string data = await FetchDataAsync();
Console.WriteLine(data);Best practices
- Name async methods with an "Async" suffix (GetDataAsync, not GetData) - a strong, widely followed C# convention
- Use async Task instead of async void for any method except top-level event handlers - async void methods cannot be awaited and make error handling much harder
- Await asynchronous operations all the way up the call chain rather than blocking on them with .Result or .Wait(), which can cause deadlocks in some contexts (like UI apps)
- Reserve async/await for genuinely I/O-bound work (network, disk, database) - it does not speed up CPU-bound computation on its own
At a glance
- Purpose
- Applications on the .NET platform
- File extension
- .cs
- Runs in
- .NET runtime
- Usually used with
- .NET SDK and libraries
Specifications & further reading
Related C# documentation
Task represents an asynchronous operation that may still be running, and Task<T> represents one that will eventually produce a value of type T. Tasks are the building block that async/await is built on top of - an async method actually returns a Task (or Task<T>) that the caller can await, check the status of, or attach continuations to.Task.WhenAll & Task.WhenAny
Task.WhenAll() lets you run multiple independent asynchronous operations concurrently and await all of them together, completing once every task finishes - much faster than awaiting them one at a time. Task.WhenAny() completes as soon as the first of several tasks finishes, useful for timeout patterns or taking whichever result arrives first.CancellationToken
CancellationToken provides a standard, cooperative way to signal that an asynchronous operation should stop before it completes naturally. A CancellationTokenSource creates the token and controls when cancellation is requested; the token itself is passed into async methods, which check it periodically (or pass it to another cancellable operation) and can throw an OperationCanceledException to unwind cleanly.Async Pitfalls: void vs Task, ConfigureAwait
A few recurring mistakes trip up many C# developers new to async: using async void instead of async Task (which makes exceptions impossible to catch normally), and blocking on async code with .Result or .Wait() (which can cause a deadlock in contexts with a synchronization context, like older ASP.NET or WPF apps). Understanding these pitfalls up front avoids some of the most common async-related bugs.