The language support for async allows for awaitables to control their own scheduling. There is default scheduling that kicks in when you await a Task, but there are many ways you can change the default behavior with a little bit more code.
Specifically, await is intended to do the following:
- Test to see if the awaitable is "done" (GetAwaiter().IsCompleted).
- If (and only if) the awaitable wasn't done, ask for it to schedule the rest of the method (GetAwaiter().OnCompleted(...))
- "Realize" the awaitable's result. This means either give back the returned value or ensure that the exceptions encountered reemerge.
So keep in mind that if the awaitable claimed it was "done", then nothing is ever scheduled.
Task.Yield() is novel because it gives back an awaitable that is never done, for the express purpose of giving you a way to explicitly stop execution for now, and immediately schedule the rest up for execution. It uses the ambient context, but there are many other ways to do similarly without ambient contexts.
An example of overriding the default behavior is when you await an incomplete task, but using the ConfigureAwait(false) method. ConfigureAwait(false) wraps the task in a special awaitable that always uses the default task scheduler, effectively always resuming on the thread pool. 'false' is there to explicitly ignore the ambient sync context.
There isn't a Task.Yield().ConfigureAwait(false), but consider the following hypothetical:
// ... A ...
await Task.Yield().ConfigureAwait(false);
// ... B ...
The above can be pretty much achieved by
// ... A ...
await Task.Run(() => {
// ... B ...
});
There is a little more explicitness and nesting there, but this isn't necessarily bad considering what's happening. Part 'A' always runs on the invoking thread, whereas part 'B' always runs on the thread pool. There are definitely differences on how you should look at code that is in sections A and B, so thus having some more curlies in between should hopefully get people to pause before assuming both sections are the same context.
TaskScheduler
in fine in most cases. – Unzip