The document provides an agenda for a presentation on the Task Parallel Library (TPL) and async/await in .NET. The presentation covers topics like threads and blocking vs non-blocking code, asynchronous programming models before async/await, the lifecycle of async operations, common misconceptions about async/await, differences between CPU-bound and I/O-bound work, exception handling, progress/cancellation, unit testing, combinators like WhenAll and WhenAny, and tips/tricks for async programming.
2. Agenda
• Introduction
• Life Before Async/Await
• Synchronization context
• The Lifecycle of an Async Operation
• Misconception about async/await
• Difference between CPU bound work and I/O work
• Handling Exceptions
• Report Progress/Cancellation of a task
• Unit Testing
• Combinators
• Tips and tricks
3. Introduction
• What is Thread?
In computer science, a thread of execution is the smallest unit of processing that can be
scheduled by an operating system.
8. Synchronization context
• It represents a target for work
• It’s been in the framework for a while, but we generally haven’t had to worry about it.
• For example, in Winforms, if you get the current SynchronizationContext and do Post on it, it
does a Control.BeginInvoke. That's how Winforms gets onto the UI thread.
• And ASP.Net current synchronization context, when you do Post() on it, it schedules work to be
done in its own way.
• There are about 10 in the framework, and you can create more.
• And this is the key way that the await keyword knows how to put you back where you were.
• So when you do await, it first captures the current SyncContext before awaiting.
• When it resumes, it uses SyncContext.Post() to resume "in the same place" as it was before.
10. Misconception about async/await
• In each async method you write, some code will be before the first occurrence of the await
keyword. Equally, some code is in the expression that gets awaited. This code always runs in
the calling thread. Nothing interesting happens before the first await.
• This is one of the most common misconceptions about async. Async never schedules your
method to run on a background thread. The only way to do that is using something like
Task.Run, which is explicitly for that purpose.
11. Difference between CPU bound work and I/O work
CPU bound work
* CPU-bound means things like LINQ-to-objects, or iterations, or computationally-intensive inner
loops.
*Parallel.ForEach and Task.Run are good ways to put these CPU-bound workloads on the
threadpool.
*Use of threads will never increase throughput on a machine that’s under load.
I/O bound work
*Async methods are intended to be non-blocking operations. An await expression in an async method
doesn’t block the current thread while the awaited task is running. Instead, the expression signs up the rest
of the method as a continuation and returns control to the caller of the async method.(Ex. Database
requests, network access requests).
12. Exceptions in Async Code
Exceptions in Async Task-Returning Methods
async Task Catcher()
{
try
{
await Thrower();
}
catch (Exception)
{
// Execution will reach here
}
}
13. Exceptions in Async void Methods
Exceptions that leave an async void method are rethrown in the calling thread:
• If there was a SynchronizationContext when the async method was called, the exception is
Posted to it.
• If not, it is thrown on the thread pool.
14. Exceptions in Async void Methods (cont.)
Handle Exceptions in Async void
• In case of Console and Windows Forms application subscribe to
“AppDomain.CurrentDomain.UnhandledException” event.
• In case of Windows Store App subscribe to “Application.UnhandledException” event
15. AggregateException and WhenAll
List<Task> tasks = new List<Task> { Thrower1(), Thrower2()};
Task result = Task.WhenAll(tasks);
try
{
await result ;
}
catch (Exception)
{
foreach (Exception ex in result.Exception.InnerExceptions)
{}
}
16. Combinators
1. Task.WhenAll (params Task[] tasks)
• creates a task that will complete when all of the supplied tasks have completed. It will not block
the current execution but allows you to await the tasks for completion.
2. Task.WaitAll(params Task[] tasks)
• will wait for all of the provided Task objects to complete execution.This will block the current
execution until all tasks are done.
3. Task.WhenAny
4. Task.WaitAny :
• So if you are inside an async method, you probably want to use Task.WhenAll or WhenAny and
use await to get the results.
17. Tips n Tricks : Dispatcher
• On the Windows Platforms there is a rule that you cannot modify UI elements from secondary
threads. On Microsoft's XAML based platforms there is a member that exists on most UI
objects called the Dispatcher that can be used to marshal a call to the proper thread.
• Demo
• The CoreDispatcherPriority enumeration has these members.
18. Tips n Tricks : TaskCompletionSource
• Is a class which wraps a Task whose state
we can manually control. This is more
easily understood with an example
• It Mostly use it when only a event base
API is available
• Demo
19. Tips n Tricks : Configure await
• “Await task” uses the sync context
• 1. It captures the current SyncContext before awaiting.
• 2. Upon task completion, it calls SyncContext.Post() to resume “where you were before”
• You can use “await task.ConfigureAwait(false)”
• This suppresses step 2; instead if possible it resumes “on the thread that completed the task”
• Demo
20. Tips n Tricks : DeadLock
• Async All the Way
You should avoid mixing async and blocking code. Mixed async and blocking code can cause deadlocks,
more-complex error handling and unexpected blocking of context threads. The exception to this
guideline is the Main method for console applications, or—if you’re an advanced user—managing a
partially asynchronous codebase. Figure 5 The “Async Way” of Doing Things
• Demo
To Do This … Instead of This … Use This
Retrieve the result of a background task Task.Wait or Task.Result await
Wait for any task to complete Task.WaitAny await Task.WhenAny
Retrieve the results of multiple tasks Task.WaitAll await Task.WhenAll
Wait a period of time Thread.Sleep await Task.Delay
Editor's Notes
Notes
-A thread is a single sequential flow of control within a program.
-A thread in computer science is short for a thread of execution. Threads are a way for a program to divide (termed "split") itself into two or more simultaneously (or pseudo-simultaneously) running tasks. Threads and processes differ from one operating system to another but, in general, a thread is contained inside a process and different threads in the same process share same resources while different processes in the same multitasking operating system do not.
To Do: Add table comparison.
1-The user clicks the button, so the event handler GetButton_OnClick is queued.
2. The UI thread executes the first half of GetButton_OnClick, including the call to
GetFaviconAsync.
3. The UI thread continues into GetFaviconAsync and executes the first half of it,
including the call to DownloadDataTaskAsync.
4. The UI thread continues into DownloadDataTaskAsync, which starts the download
and returns a Task.
5. The UI thread leaves DownloadDataTaskAsync, and reaches the await in
GetFaviconAsyncAsync.
6. The current SynchronizationContext is captured—it’s the UI thread.
7. GetFaviconAsync is paused by the await, and the Task from DownloadDataTask
Async is told to resume it when done (with the captured SynchronizationContext).
8. The UI thread leaves GetFaviconAsync, which returned a Task, and reaches the
await in GetButton_OnClick.
9.Similarly, GetButton_OnClick is paused by the await.
10. The UI thread leaves GetButton_OnClick, and is freed to work on other user actions.
11. The download finishes, so the IO completion port queues the logic in
DownloadDataTaskAsync to handle that.
12. The IO completion port thread sets the Task that was returned from DownloadData
TaskAsync to complete.
13. The IO completion port thread runs code inside Task to handle completion, which
calls Post on the captured SynchronizationContext (the UI thread) to continue.
14. The IO completion port thread is freed to work on other IO.
15. The UI thread finds the Posted instruction and resumes GetFaviconAsync, executing
the second half of it, to the end.
16. As the UI thread leaves GetFaviconAsync, it sets the Task that was returned by
GetFaviconAsync to complete.
17. Because this time, the current SynchronizationContext is the same as the captured
one, no Post is needed, and the UI thread proceeds synchronously.
18. The UI thread resumes GetButton_OnClick, executing the second half of it, to the
end.