English
Summary
Conclusions
A TPL task describes an operation that will complete successfully, with an exception, or with cancellation. It is not a thread: computations run in the thread pool, while waiting for I/O does not occupy a thread. Task.Run starts computation; Task.WhenAll, WhenAny, and WhenEach combine tasks without blocking, while Wait and Result block the thread and may cause deadlocks. Conditional ContinueWith continuations build task graphs. Task exceptions accumulate in an AggregateException; await throws the first one. Cancellation in .NET is cooperative: a CancellationTokenSource sends a request, and the operation checks the token and throws OperationCanceledException. The compiler transforms an async method into a state machine whose continuations run in the captured synchronization context or in the pool. ValueTask, IAsyncEnumerable<T>, PeriodicTimer, and TaskCompletionSource<T> extend the model to synchronous results, data streams, periodic actions, and events. SemaphoreSlim limits concurrent operations, while async void and synchronous waiting on asynchronous code are the most common antipatterns.
Self-check questions
- How does a task differ from a thread?
- When do you use
Task.Factory.StartNewinstead ofTask.Run? What doesLongRunningprovide? - What states can a task have? Which are final states?
- How do
Task.WaitAllandTask.WhenAlldiffer? - Why can accessing
Resultcause a deadlock? - What is a continuation? How do you run a continuation only if its antecedent fails?
- How does a child task differ from a nested task?
- Why is a task's
Exceptionproperty of typeAggregateException? What areFlattenandHandlefor? - How do you retrieve all exceptions after
await Task.WhenAll(...)? - Describe cooperative cancellation. What are the roles of
CancellationTokenSourceandCancellationToken? - Under what condition does a task enter the
Canceledstate rather thanFaulted? - How does the compiler transform an
asyncmethod? What does the state machine's state field store? - What is a synchronization context? When do you use
ConfigureAwait(false)? - How do compute operations differ from I/O operations in terms of
async/await? - When is
ValueTaskappropriate? What are its limitations? - What is
TaskCompletionSource<T>for? Why useRunContinuationsAsynchronously? - How do you limit the number of concurrent asynchronous operations?
- Why are
async voidand.Resultconsidered antipatterns?
Useful links
- Task Parallel Library (TPL): https://learn.microsoft.com/dotnet/standard/parallel-programming/task-parallel-library-tpl
- Task-based asynchronous programming: https://learn.microsoft.com/dotnet/standard/parallel-programming/task-based-asynchronous-programming
- Exception handling in TPL: https://learn.microsoft.com/dotnet/standard/parallel-programming/exception-handling-task-parallel-library
- Cancellation in managed threads: https://learn.microsoft.com/dotnet/standard/threading/cancellation-in-managed-threads
- Asynchronous programming with
asyncandawait: https://learn.microsoft.com/dotnet/csharp/asynchronous-programming/ - Task-based Asynchronous Pattern (TAP): https://learn.microsoft.com/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap
- Consuming TAP: combinators, progress, cancellation: https://learn.microsoft.com/dotnet/standard/asynchronous-programming-patterns/consuming-the-task-based-asynchronous-pattern
TaskCompletionSource<TResult>: https://learn.microsoft.com/dotnet/api/system.threading.tasks.taskcompletionsource-1- Debugging multithreaded and asynchronous programs in Rider: https://www.jetbrains.com/help/rider/Debugging_Multithreaded_Applications.html