Since the introduction of C#, async/await concepts are still misunderstood by many developers.
Async programming tries to solve three problems (Offloading, Concurrency, Scalability) in a mean abstraction.
This presentation is a good starting point to asynchronous programming in .net. There are many links and references, so do not hesitate to go deeper.
2. Agenda
• Introduction
• Brief History
• Refresher of the TPL
• What’s different since 4.5 ?
• Best Practices
• Working with Async
Asynchronous programming is a
means of parallel programming in
which a unit of work runs
separately from the main
application thread and notifies the
calling thread of its completion,
failure or progress. Why do we
need it now ?
4. What does asynchrony really mean?
Synchronous
Perform something here and now.
I’ll regain control to execute something
else when it’s done.
Asynchronous
Initiate something here and now.
I’ll regain control to execute something else
“immediately”.
How an operation is invoked
implies nothing about the
implementation of the workload itself.
Async Clinic
5. Sync vs Async
“Pause for 10 seconds, then output 'Hello' to the console.”
Synchronous
Asynchronous
Both “async over sync” and “sync over async” can be problematic
if you don’t completely understand the implementation.
7. Going Async
public class MyClass
{
public int Read(byte [] buffer, int offset, int count);
}
public class MyClass
{
public Task<int> ReadAsync(byte [] buffer, int offset, int count);
}
10 years
1.0 (2002)
4.5 (2012)
8. Asynchronous Programming Model (APM)
http://msdn.microsoft.com/en-us/library/ms228963.aspx
• Introduced in .net 1.1 (no async support before)
• Asynchronous operations require BeginXX and EndXX methods
– Example : BeginWrite and EndWrite for asynchronous write operations).
• No longer recommended
• Several APIs and legacy code still use this pattern
public class MyClass
{
public IAsyncResult BeginRead(
byte [] buffer, int offset, int count,
AsyncCallback callback, object state);
public int EndRead(IAsyncResult asyncResult);
}
9. Event-based Asynchronous Pattern (EAP)
http://msdn.microsoft.com/en-us/library/ms228969.aspx
• Introduced in .net 2.0
• Requires a method that has the Async suffix, and also requires
one or more events, event handler delegate types, and
EventArg-derived types.
public class MyClass
{
public void ReadAsync(byte [] buffer, int offset, int count);
public event ReadCompletedEventHandler ReadCompleted;
}
public delegate void ReadCompletedEventHandler(
object sender, ReadCompletedEventArgs eventArgs);
public class ReadCompletedEventArgs : AsyncCompletedEventArgs
{
public int Result { get; }
}
10. Task-based Asynchronous Pattern (TAP)
http://msdn.microsoft.com/en-us/library/hh873175.aspx
• Introduced in .net 4.0 but greatly improved in 4.5
• Uses a single method to represent the initiation and
completion of an asynchronous operation.
• Recommended approach to asynchronous programming in
the .NET Framework.
• Very similar to the synchronous version
• Interop with Other Asynchronous Patterns and Types is
supported (EAP<>TAP, APM<>TAP)
public class MyClass
{
public Task<int> ReadAsync(byte [] buffer, int offset, int count);
}
12. What is a Task/Task<> ?
• A Task represents an asynchronous operation
– resembles a thread or ThreadPool work item, but at a higher level of abstraction
– Similar to promises in Javascript
• Task can only run from start to finish once
– you cannot run the same task object two times. Have to create another Task object for
running the same code
• More efficient and more scalable use of system resources.
– Tasks are queued to the ThreadPool, which has been enhanced with algorithms that
determine and adjust to the number of threads and that provide load balancing to
maximize throughput. This makes tasks relatively lightweight, and you can create many
of them to enable fine-grained parallelism.
• More programmatic control than is possible with a thread or work item.
– Rich set of APIs that support waiting, cancellation, continuations, robust exception
handling, detailed status, custom scheduling, and more.
• Task (as it is used by the TPL) is pretty much completely different than Task (as it is
used by async).
TPL is the preferred API for writing multi-threaded,
asynchronous, and parallel code
13. Task<T> Properties
Task<T> has important properties.
Don’t reinvent the wheel when consuming Task and Task<T> !
14. Starting a Task
• Threre are many ways to start a task.
• Most of time, we don’t need to start a Task
by yourself ; The API/Framework method
will give a task.
– eg HttpClient, StreamReader, …
• If you still need to start a Task, use
– Task.Run
– Task.Factory.StartNew for a full control
• About Task.Run
– Do not use it just to “provide something
awaitable” aka a fake-asynchronous method
– CPU-bound tasks only
Task.Run vs Task.Factory.StartNew
15. Cancelling a Task
• Cancellation is supported through the use of
CancellationToken (via
CancellationTokenSource ) to request
cancellation
• You can terminate an operation
– By returning the delegate (In the case the
status is RantoCompletion and not Canceled)
– By throwing a OperationCanceledException via
ThrowIfCancellationRequested
• Cancellation token are present in all async API
Task Cancellation
16. Exceptions handling
• User-code can throw intentionally (or not
any) any kind of exceptions.
• Exceptions are propagated back to the
joining code when using Task.Wait(),
Task.Result,await …
– Be sure to always surround this with a
try/catch statement
• Task infrastructure wraps thrown
exceptions in AggregateException
instance. In that case, the task status is
Faulted and Task.Exception contains
Read more on TPL and Exceptions
17. Task Continuations
• A continuation task is an asynchronous task that is invoked by another task
– Traditionally, this has been done by using callback methods
• Continuations are relatively easy to use, but are nevertheless very powerful and
flexible. For example, you can:
– pass data from the antecedent to the continuation
– specify the conditions under which the continuation will be invoked or not invoked
– cancel a continuation either before it starts or cooperatively as it is running
– invoke multiple continuations from the same antecedent
– invoke one continuation when all or any one of multiple antecedents complete
– chain continuations one after another to any arbitrary length
– use a continuation to handle exceptions thrown by the antecedent
– …
• Many continuations options (NotOnFaulted, OnlyOnFaulted, ..)
• Continuation Tasks is an important topic to achieve « Async all the way »
Continuation Tasks
20. What’s different now ?
Asynchronous programming
with .NET 4 is a little easier.
Asynchronous programming
with .NET 4.5 is a lot easier.
21. Task = new Task
TPL 4.5 Performance improvements
22. TPL at the Core layer
Application area Supporting APIs that contain async methods
Web access HttpClient , SyndicationClient
Working with files StorageFile, StreamWriter, StreamReader, XmlReader
Working with images MediaCapture, BitmapEncoder, BitmapDecoder
WCF programming Synchronous and Asynchronous Operations
Asynchrony is essential for activities that are potentially
blocking, ; so async programming was added in several APIs
from the .NET Framework 4.5 and the Windows Runtime
23. New Task Methods
• Task.Run : Use it to offload work as a Task or Task<TResult> to the thread pool
• Task.Delay : Use the Delay method to introduce pauses into an asynchronous
method’s execution
• Task.FromResult : Use the FromResult<TResult> method in scenarios where data
may already be available and just needs to be returned from a task-returning
method lifted into a Task<TResult>:
• Task.WhenAll : Use the WhenAll method to asynchronously wait on multiple
asynchronous operations that are represented as tasks
• Task.WhenAny : Use the WhenAny method to asynchronously wait for just one of
multiple asynchronous operations represented as tasks to complete
• …
24. New keywords : async/await
added in .net 4.5 & C# 5
• Allow writing/debugging async code almost as if it is a usual synchronous code
• Both keywords - async and await - always work together.
– await without async is not allowed.
– async without await is allowed, but not the method executes as a synchronous method
Use the async modifier to specify that a
method, lambda expression, or anonymous
method is asynchronous.
The async keyword was mainly added to
avoid backwards compatibility problems
when using the await keyword
An async method can have a return type of
Task, Task<TResult>, or void
The await operator is applied to a task in an
asynchronous method to suspend the
execution of the method until the awaited
task completes
26. Await/await with .net 4.0
• It’s possible to use async/await in projects targeting .net 4.0
• It does not include the ASP.NET runtime changes necessary for
proper async/await support, so if you install it into an ASP.NET 4.0 project, the
code will compile but will not work correctly
• It’s better to upgade to 4.5
27. There is no thread
“if I am awaiting an operation,
there must be a thread that is doing the
wait! It’s probably a thread pool thread.
Or an OS thread! Or something with a
device driver…”
There is no thread
“Regardless of the type of I/O request,
internally I/O operations issued to a driver
on behalf of the application are
performed asynchronously”,
Windows Internals
29. How do I know which method is async or not ?
The .NET Framework 4.5 contains many members that work with async and await. You
can recognize these members by the "Async" suffix that’s attached to the member
name and a return type of Task or Task<TResult>.
Library methods shouldn’t lie.
Be honest. Use “XxAsync” if, and only if, you’re
not thread-bound (with a few notable
exceptions).
Suffix should help caller to understand
implementation.
30. TAP Guidelines
There are many new await-friendly techniques that should be used instead of the old
blocking techniques. If you have any of these Old examples in your new async code,
you’re Doing It Wrong. TAP Guidelines
31. Async all the way
• “await and async” is poison.
– Await/await isn’t intended to be used in just a single function, but for an entire flow in
your application.
– Once you will add them somewhere in your code. These keywords will propagate all of
the way up to the top of a logical stack.
• Asynchronous code works best if asynchronous code calls and is called by other
asynchronous code
• Don’t mix synchronous and asynchronous code (without carefully considering the
consequences)
– bad idea to block on async code by calling Task.Wait or Task.Result.
– Mixed async and blocking code can cause deadlocks, more-complex error handling and
unexpected blocking of context threads
• Exceptions
– Console Applications, Unit Tests
32. Asynchronous wrappers for synchronous methods?
“async over sync”
• Two primary benefits to asynchrony: scalability and offloading (e.g.
responsiveness, parallelism)
• Scalability
– still consuming the same amount of resources (even a bit more)
– Don’t put Task.Run everywhere to achieve async over sync. Use a thread from the
thread pool.
• Offloading
– if a consumer of your library wants to use the synchronous method asynchronously,
they can do so on their own
Async
http://blogs.msdn.com/b/pfxteam/archive/2012/03/24/10287244.aspx
33. Synchronous wrappers for asynchronous methods?
“sync over async”
• Avoid exposing a synchronous method that just wraps the asynchronous
implementation
– hides from the consumer the true nature of the implementation
– If the consumer chooses to block waiting for the asynchronous
implementation to complete, that’s up to the caller
• Can lead to significant problems with the application, such as hangs
http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx
34. Async with asp.net (API or MVC)
What benefits ?
Introduction to Async/Await on ASP.NET
In the case of I/O bound operations (whether that's disk
I/O or network I/O), the waiting that a thread might
normally do is purposeless. Using an async version of the
I/O method allows the worker thread -- which are
generally in limited supply -- to go back into the worker
pool to start servicing another request. When the I/O is
ready, and a thread from the worker pool is available,
then the original request can be completed. This can have
a fairly substantial benefit in scalability of the server,
because it means servicing lots more requests with far
fewer resources.
Don’t forget Parallelization : do not call
sequentially N operations but parallelize
work, and therefore return the data to the
client sooner
35. Tasks and asp.net MVC
The way to build asynchronous controllers has been completely changed compared to
how it was done previously with the AsyncController superclass. This class and the
inherent complexity in using it are gone.
Async
36. Task in asp.net Web Api
Mark your Api action with
async + Task<Result>
Message handlers also
support async/await.
(Cleaner than writing it
with a continuation task).
38. Async is for “long” tasks
As there is a small overhead of using async (SynchronizationContext, Task Creation,
Task Scheduling, Queueing…) ; so Do not put async everwhere. It won’t help.
• Use where .NET 4.5 framework is Async
– Network I/O
– File I/O
– Database I/O
• CAUTION! (not all providers are async)
– Remote Service Calls
• Use for CPU-bound work
– > 50ms with a user waiting
– For server code, it depends
39. Consider using await instead of ContinueWith/Unwrap
• Async/await is better
– Easier to read
– Fewer context switches
– Better memory footprint –
especially with chained tasks
– Less startup overhead
TPL 4.5 Performance improvements
40. Use cached Tasks when possible
“While we have strived to slim down Task and
eliminate unnecessary allocations in .NET 4.5, the
optimal allocation is one that never happens.
Sometimes it is possible to cache a single instance of
a frequently used Task, eliminating the need to
continually re-allocate the Task.”, Stephen Toub
• Cache the Tasks, not the Data
• reuse completed tasks
• Use completed & static Tasks
– Use Task.FromResult
41. Encode closure information into a Task’s state object
Compilation
• Pass values by parameter where possible
• Only capture the variable you are going to use.
– Use local variables when necessary
42. Don’t block on async code
UI Client UI Asp.net
Deadlock ! Why ?
• After you await a Task, when the method continues it will continue in a context.
• GUI and ASP.NET applications have a SynchronizationContext that permits only
one chunk of code to run at a time
Don’t block on async code
43. Don't block on async code
Call ConfigureAwait
• Don’t Wait on Tasks
– Let the runtime schedule the continuations
• Don’t access Task.Result unless it’s completed
– Task.Result is blocking
• If you must, be aware of synchronized contexts:
– UI Threads
– ASP.NET Threads
• For API developpers
Don’t block on Tasks; use async all
the way down
– Call ConfigureAwait(false) It’s all about SynchronizationContext
44. Use Async void for event Handlers
void is a possible return type (with Task and Task<Result>) for an async method
• Principles
– Async void is a “fire-and-forget” mechanism...
– The caller is unable to know when an async void has finished
– The caller is unable to catch exceptions thrown from an async void
• Guidance
– Use async void methods only for top-level event handlers (and their like)
– Use async Task-returning methods everywhere else
– When you see an async lambda, verify it
Async void Tips
45. TPL Dataflow
• TPL DataFlow is a library for building asynchronous data processing
application
• Not distributed with the .NET Framework 4.5, avaible via Nuget
• A natural extension of the TPL library that allows developers to create
data-processing pipelines in their applications
• Many concepts of Actor model
TPL Dataflow on MSDN
46. Not Async
Not Running
Asynchronously. Why ?
‘async’ don’t forks.
Use Task.Run to offload
47. Method not completing
Awaited task
sometimes never
completes. Why ?
Always complete Tasks
when the underlying
operation has ended
Deadlocking UI thread.
Why ?
Don’t synchronously wait on the UI thread.
Use ConfigureAwait(false) whenever possible.