Async and Await
Asynchronous programming patterns, deadlock avoidance, async locks, context switching, and the Task-based Asynchronous Pattern.
Stephen Cleary
Concurrency in C# Cookbook 1: Asynchronous, Parallel, and Multithreaded Programming
Async and Await intro 2
Don’t Block on Async Code 3
Stephen Toub
Should I expose asynchronous wrappers for synchronous methods? 4
Notes
There’s one other important guideline when it comes to async methods: once you start using
async, it’s best to allow it to grow through your code. If you call an async method, you should (eventually) await the task it returns. Resist the temptation to callTask.Wait,Task<TResult>.Result, orGetAwaiter().GetResult()— doing so could cause a deadlock.
Consider the following method:
async Task WaitAsync()
{
// This await will capture the current context ...
await Task.Delay(TimeSpan.FromSeconds(1));
// ... and will attempt to resume the method here in that context.
}
void Deadlock()
{
// Start the delay.
Task task = WaitAsync();
// Synchronously block, waiting for the async method to complete.
task.Wait();
}
- The code in this example will deadlock if called from a UI or ASP.NET Classic context because both of those contexts only allow one thread in at a time
Deadlockwill callWaitAsync, which begins the delayDeadlockthen (synchronously) waits for that method to complete, blocking the context thread- When the delay completes, await attempts to resume
WaitAsyncwithin the captured context, but it cannot because there’s already a thread blocked in the context, and the context only allows one thread at a time - Deadlock can be prevented two ways:
- use
ConfigureAwait(false)withinWaitAsync(which causes await to ignore its context) - or await the call to
WaitAsync(makingDeadlockinto an async method)
- use
WARNING If you use async, it’s best to use async all the way.
WARNING Using
Taskfor parallel processing is completely different than usingTaskfor asynchronous processing.
The Task type serves two purposes in concurrent programming: it can be a parallel task or an asynchronous task. Parallel tasks may use blocking members, such as Task.Wait, Task.Result, Task.WaitAll, and Task.WaitAny. Parallel tasks also commonly use AttachedToParent to create parent/child relationships between tasks. Parallel tasks should be created with Task.Run or Task.Factory.StartNew.
In contrast, asynchronous tasks should avoid blocking members, and prefer await, Task.WhenAll, and Task.WhenAny. Asynchronous tasks should not use AttachedToParent, but they can form an implicit kind of parent/child relationship by awaiting another task.
Async Locks
Chapter 12.2 5
Problem You have some shared data and need to safely read and write it from multiple code blocks, which may be using await.
Solution The .NET framework SemaphoreSlim type has been updated in .NET 4.5 to be compatible with async:
class MyClass
{
// This lock protects the _value field.
private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1);
private int _value;
public async Task DelayAndIncrementAsync()
{
await _mutex.WaitAsync();
try
{
int oldValue = _value;
await Task.Delay(TimeSpan.FromSeconds(oldValue));
_value = oldValue + 1;
}
finally
{
_mutex.Release();
}
}
}
You can also use the AsyncLock type from the Nito.AsyncEx library:
class MyClass
{
// This lock protects the _value field.
private readonly AsyncLock _mutex = new AsyncLock();
private int _value;
public async Task DelayAndIncrementAsync()
{
using (await _mutex.LockAsync())
{
int oldValue = _value;
await Task.Delay(TimeSpan.FromSeconds(oldValue));
_value = oldValue + 1;
}
}
}
Context Switch
- What is context switching in operating system? 6
ThreadPool.GetAvailableThreads7- The cost of context switches 8
- Does async/await increase context switching? 9
Task-Based Asynchronous Pattern
TAP in .NET: Introduction and overview 10
Implementing the Task-based Asynchronous Pattern 11
Consuming the Task-based Asynchronous Pattern 12
Interop with Other Asynchronous Patterns and Types 13
Asynchronous Programming Model (APM) 14
Cancel async tasks after a period of time 15
Cancellation
CancellationTokentimeout vsTask.Delayand timeout 16- Coalescing CancellationTokens from Timeouts 17
- How to use CancellationTokens to cancel tasks in the Azure SDK for .NET 18
Async Enumerables
- Iterating with Async Enumerables in C# 8 19
- Pagination with the Azure SDK for .NET 20
System.Linq.Async21
Dynamic Parallelism 22