Do the New C# 5.0 'Async' and 'Await' Keywords Use Multiple Cores

Do the new C# 5.0 'async' and 'await' keywords use multiple cores?

Two new keywords added to the C# 5.0 language are async and await, both of which work hand in hand to run a C# method asynchronously without blocking the calling thread.

That gets across the purpose of the feature, but it gives too much "credit" to the async/await feature.

Let me be very, very clear on this point: await does not magically cause a synchronous method to run asynchronously. It does not start up a new thread and run the method on the new thread, for example. The method you are calling has to be the thing that knows how to run itself asynchronously. How it chooses to do so is its business.

My question is, do these methods actually take advantage of multiple cores and run in parallel or does the async method run in the same thread core as the caller?

Again, that is entirely up to the method you call. All that await does is instruct the compiler to rewrite the method into a delegate that can be passed as the continuation of the asynchronous task. That is, the await FooAsync() means "call FooAsync() and whatever comes back must be something that represents the asynchronous operation that just started up. Tell that thing that when it knows that the asynchronous operation is done, it should call this delegate." The delegate has the property that when it is invoked, the current method appears to resume "where it left off".

If the method you call schedules work onto another thread affinitized to another core, great. If it starts a timer that pings some event handler in the future on the UI thread, great. await doesn't care. All it does is makes sure that when the asynchronous job is done, control can resume where it left off.

A question you did not ask but probably should have is:

When the asynchronous task is finished and control picks up where it left off, is execution in the same thread as it was before?

It depends on the context. In a winforms application where you await something from the UI thread, control picks up again on the UI thread. In a console application, maybe not.

Does the use of async/await create a new thread?

In short NO

From Asynchronous Programming with Async and Await : Threads

The async and await keywords don't cause additional threads to be
created. Async methods don't require multithreading because an async
method doesn't run on its own thread. The method runs on the current
synchronization context and uses time on the thread only when the
method is active. You can use Task.Run to move CPU-bound work to a
background thread, but a background thread doesn't help with a process
that's just waiting for results to become available.

How and when to use ‘async’ and ‘await’

When using async and await the compiler generates a state machine in the background.

Here's an example on which I hope I can explain some of the high-level details that are going on:

public async Task MyMethodAsync()
{
Task<int> longRunningTask = LongRunningOperationAsync();
// independent work which doesn't need the result of LongRunningOperationAsync can be done here

//and now we call await on the task
int result = await longRunningTask;
//use the result
Console.WriteLine(result);
}

public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation
{
await Task.Delay(1000); // 1 second delay
return 1;
}

OK, so what happens here:

  1. Task<int> longRunningTask = LongRunningOperationAsync(); starts executing LongRunningOperation

  2. Independent work is done on let's assume the Main Thread (Thread ID = 1) then await longRunningTask is reached.

    Now, if the longRunningTask hasn't finished and it is still running, MyMethodAsync() will return to its calling method, thus the main thread doesn't get blocked. When the longRunningTask is done then a thread from the ThreadPool (can be any thread) will return to MyMethodAsync() in its previous context and continue execution (in this case printing the result to the console).

A second case would be that the longRunningTask has already finished its execution and the result is available. When reaching the await longRunningTask we already have the result so the code will continue executing on the very same thread. (in this case printing result to console). Of course this is not the case for the above example, where there's a Task.Delay(1000) involved.

Writing multithreaded methods using async/await in .Net 4.5

So to start with you'll need a method that does the very expensive work synchronously:

public void DoLotsOfWork<T>(T[] data, int start, int end) 
{
Thread.Sleep(5000);//placeholder for real work
}

Then we can use Task.Run to start multiple instances of this work in a threadpool thread.

List<Task> tasks = new List<Task>();
for(int i = 0; i < 4; i++)
{
tasks.Add(Task.Run(()=>DoLotsOfWork(data, start, end));
}

Then we can do a non-blocking wait until all of them are done:

await Task.WhenAll(tasks);

Is async()=await funcAsync() equivalent to ()=funcAsync() in C#?

I want to know if the two are equivalent, and if they are different

Yes, They are different.

This one will create a method for Func<ICacheEntry, Task>

e=>_service.GetAllAsync()

but async ... await will create a state machine code which means the method could be awaitable automatically.

async e=> await _service.GetAllAsync()

Here is a sample code, Although this code looks a little stupid but I want to show the different part of code.

Action s = ()=>  Task.Delay(100);

code of normal delegate

Action s = async ()=> await Task.Delay(100);

code of async delegate

If async-await doesn't create any additional threads, then how does it make applications responsive?

Actually, async/await is not that magical. The full topic is quite broad but for a quick yet complete enough answer to your question I think we can manage.

Let's tackle a simple button click event in a Windows Forms application:

public async void button1_Click(object sender, EventArgs e)
{
Console.WriteLine("before awaiting");
await GetSomethingAsync();
Console.WriteLine("after awaiting");
}

I'm going to explicitly not talk about whatever it is GetSomethingAsync is returning for now. Let's just say this is something that will complete after, say, 2 seconds.

In a traditional, non-asynchronous, world, your button click event handler would look something like this:

public void button1_Click(object sender, EventArgs e)
{
Console.WriteLine("before waiting");
DoSomethingThatTakes2Seconds();
Console.WriteLine("after waiting");
}

When you click the button in the form, the application will appear to freeze for around 2 seconds, while we wait for this method to complete. What happens is that the "message pump", basically a loop, is blocked.

This loop continuously asks windows "Has anyone done something, like moved the mouse, clicked on something? Do I need to repaint something? If so, tell me!" and then processes that "something". This loop got a message that the user clicked on "button1" (or the equivalent type of message from Windows), and ended up calling our button1_Click method above. Until this method returns, this loop is now stuck waiting. This takes 2 seconds and during this, no messages are being processed.

Most things that deal with windows are done using messages, which means that if the message loop stops pumping messages, even for just a second, it is quickly noticeable by the user. For instance, if you move notepad or any other program on top of your own program, and then away again, a flurry of paint messages are sent to your program indicating which region of the window that now suddenly became visible again. If the message loop that processes these messages is waiting for something, blocked, then no painting is done.

So, if in the first example, async/await doesn't create new threads, how does it do it?

Well, what happens is that your method is split into two. This is one of those broad topic type of things so I won't go into too much detail but suffice to say the method is split into these two things:

  1. All the code leading up to await, including the call to GetSomethingAsync
  2. All the code following await

Illustration:

code... code... code... await X(); ... code... code... code...

Rearranged:

code... code... code... var x = X(); await X; code... code... code...
^ ^ ^ ^
+---- portion 1 -------------------+ +---- portion 2 ------+

Basically the method executes like this:

  1. It executes everything up to await

  2. It calls the GetSomethingAsync method, which does its thing, and returns something that will complete 2 seconds in the future

    So far we're still inside the original call to button1_Click, happening on the main thread, called from the message loop. If the code leading up to await takes a lot of time, the UI will still freeze. In our example, not so much

  3. What the await keyword, together with some clever compiler magic, does is that it basically something like "Ok, you know what, I'm going to simply return from the button click event handler here. When you (as in, the thing we're waiting for) get around to completing, let me know because I still have some code left to execute".

    Actually it will let the SynchronizationContext class know that it is done, which, depending on the actual synchronization context that is in play right now, will queue up for execution. The context class used in a Windows Forms program will queue it using the queue that the message loop is pumping.

  4. So it returns back to the message loop, which is now free to continue pumping messages, like moving the window, resizing it, or clicking other buttons.

    For the user, the UI is now responsive again, processing other button clicks, resizing and most importantly, redrawing, so it doesn't appear to freeze.

  5. 2 seconds later, the thing we're waiting for completes and what happens now is that it (well, the synchronization context) places a message into the queue that the message loop is looking at, saying "Hey, I got some more code for you to execute", and this code is all the code after the await.

  6. When the message loop gets to that message, it will basically "re-enter" that method where it left off, just after await and continue executing the rest of the method. Note that this code is again called from the message loop so if this code happens to do something lengthy without using async/await properly, it will again block the message loop

There are many moving parts under the hood here so here are some links to more information, I was going to say "should you need it", but this topic is quite broad and it is fairly important to know some of those moving parts. Invariably you're going to understand that async/await is still a leaky concept. Some of the underlying limitations and problems still leak up into the surrounding code, and if they don't, you usually end up having to debug an application that breaks randomly for seemingly no good reason.

  • Asynchronous Programming with Async and Await (C# and Visual Basic)
  • SynchronizationContext Class
  • Stephen Cleary - There is no thread well worth a read!
  • Channel 9 - Mads Torgersen: Inside C# Async well worth a watch!

OK, so what if GetSomethingAsync spins up a thread that will complete in 2 seconds? Yes, then obviously there is a new thread in play. This thread, however, is not because of the async-ness of this method, it is because the programmer of this method chose a thread to implement asynchronous code. Almost all asynchronous I/O don't use a thread, they use different things. async/await by themselves do not spin up new threads but obviously the "things we wait for" may be implemented using threads.

There are many things in .NET that do not necessarily spin up a thread on their own but are still asynchronous:

  • Web requests (and many other network related things that takes time)
  • Asynchronous file reading and writing
  • and many more, a good sign is if the class/interface in question has methods named SomethingSomethingAsync or BeginSomething and EndSomething and there's an IAsyncResult involved.

Usually these things do not use a thread under the hood.


OK, so you want some of that "broad topic stuff"?

Well, let's ask Try Roslyn about our button click:

Try Roslyn

I'm not going to link in the full generated class here but it's pretty gory stuff.

Async Await Infinite Regression

You can only await an async method.

That's not true. You can await anything that follows the "awaitable pattern" (something with a GetAwaiter() method, the return type of which has appropriate IsCompleted, GetResult(), and OnCompleted() members.

Note that even when you're awaiting the result of calling an async method, it really is the result that you're awaiting... and it doesn't matter that the result happened to be from an async method. As far as the compiler's concerned, you're just awaiting a Task or a Task<T>, which was the result of a method call. The async part only matters within the implementation of the method.

You can await other things as well though - for example, Task.Yield returns a YieldAwaitable which isn't a task, but which implements the awaitable pattern. You can implement the awaitable pattern yourself (and cause all kinds of fun mayhem by doing so, should you wish to).

However that async method itself needs to have an await statement inside it itself.

Again, not true - although the compiler will warn you if you don't have an await expression within an async method, as that's almost always a sign that you're doing something wrong.

Async calls with new keyword 'await'

From Eric Lippert's Blog post Asynchrony in C# 5, Part One

The designers of C# 5.0 realized that
writing asynchronous code is painful,
in so many ways. Asynchronous code is
hard to reason about, and as we've
seen, the transformation into a
continuation is complex and leads to
code replete with mechanisms that
obscure the meaning of the code.

As the article explains like iterator blocks, anonymous methods, query comprehensions and dynamic types the intent is to make something that is hard, easy.

As for Community Technical Preview bit. Typically it means that "await" will be in the next version of C#, but there's no guarantee that something about it won't change. So if you write something (code or blog posts) and its breaks don't blame them.



Related Topics



Leave a reply



Submit