First, let’s clear up some terminology: “asynchronous” (
async) means that it
may yield control back to the calling thread before it starts. In an
async
method, those “yield” points are
awaitexpressions.
This is very different than the term “asynchronous”, as (mis)used by the MSDN
documentation for years to mean “executes on a background thread”.
To futher confuse the issue,
asyncis very different than “awaitable”; there
are some
asyncmethods whose return types are not awaitable, and many
methods returning awaitable types that are not
async.
Enough about what they aren’t ; here’s what they are :
- The
async
keyword allows an asynchronous method (that is, it allowsawait
expressions).async
methods may returnTask
,Task<T>
, or (if you must)void
. - Any type that follows a certain pattern can be awaitable. The most common awaitable types are
Task
andTask<T>
.
So, if we reformulate your question to “how can I run an operation on a
background thread in a way that it’s awaitable”, the answer is to use
Task.Run:
private Task<int> DoWorkAsync() // No async because the method does not need await{ return Task.Run(() => { return 1 + 2; });}(But this pattern is a poor approach; see below).
But if your question is “how do I create an
asyncmethod that can yield back
to its caller instead of blocking”, the answer is to declare the method
asyncand use
awaitfor its “yielding” points:
private async Task<int> GetWebPageHtmlSizeAsync(){ var client = new HttpClient(); var html = await client.GetAsync("http://www.example.com/"); return html.Length;}So, the basic pattern of things is to have
asyncpre depend on “awaitables”
in its
awaitexpressions. These “awaitables” can be other
asyncmethods or
just regular methods returning awaitables. Regular methods returning
Task/
Task<T>can use
Task.Runto execute pre on a background thread,
or (more commonly) they can use
TaskCompletionSource<T>or one of its
shortcuts (
TaskFactory.FromAsync,
Task.FromResult, etc). I don’t
recommend wrapping an entire method in
Task.Run; synchronous methods should
have synchronous signatures, and it should be left up to the consumer whether
it should be wrapped in a
Task.Run:
private int DoWork(){ return 1 + 2;}private void MoreSynchronousProcessing(){ // Execute it directly (synchronously), since we are also a synchronous method. var result = DoWork(); ...}private async Task DoVariousThingsFromTheUIThreadAsync(){ // I have a bunch of async work to do, and I am executed on the UI thread. var result = await Task.Run(() => DoWork()); ...}I have an
async/
awaitintro on my blog; at the end are some good followup resources. The
MSDN docs for
asyncare unusually good, too.



