How does async/await work in C#?
Mark a method async and return Task or Task<T>, then await operations that would otherwise block. Await frees the thread instead of holding it while waiting.
async Task<string> LoadAsync(string url)
{
using var client = new HttpClient();
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}#Never block on async code
var result = LoadAsync(url).Result; // can deadlock
var result = LoadAsync(url).GetAwaiter().GetResult(); // same problem
var result = await LoadAsync(url); // correctIn a UI or classic ASP.NET context, .Result blocks the thread that the continuation needs in order to finish. Both sides wait forever.
Async all the way up. If a method awaits, its callers should await too.
#Return Task, not void
async void Bad() { } // exceptions cannot be caught — crashes the process
async Task Good() { }The single exception is an event handler, which must return void because the delegate signature demands it. Wrap its whole body in try/catch.
#Run independent work in parallel
// Sequential — 600ms
var a = await GetA();
var b = await GetB();
// Concurrent — 200ms
var taskA = GetA();
var taskB = GetB();
await Task.WhenAll(taskA, taskB);
var a = taskA.Result; // safe here — already completed#Cancellation
async Task WorkAsync(CancellationToken token)
{
await Task.Delay(1000, token);
token.ThrowIfCancellationRequested();
}Accept a CancellationToken in any long-running async method and pass it down. Callers can then abandon work that is no longer needed.
#ConfigureAwait(false) in libraries
await client.GetAsync(url).ConfigureAwait(false);In library code, this says the continuation does not need the original synchronization context. It avoids a class of deadlocks and is slightly faster. Application code generally does not need it.