What's the New C# Await Feature Do

What's the new C# await feature do?

They just talked about this at PDC yesterday!

Await is used in conjunction with Tasks (parallel programming) in .NET. It's a keyword being introduced in the next version of .NET. It more or less lets you "pause" the execution of a method to wait for the Task to complete execution. Here's a brief example:

//create and run a new task  
Task<DataTable> dataTask = new Task<DataTable>(SomeCrazyDatabaseOperation);

//run some other code immediately after this task is started and running
ShowLoaderControl();
StartStoryboard();

//this will actually "pause" the code execution until the task completes. It doesn't lock the thread, but rather waits for the result, similar to an async callback
// please so also note, that the task needs to be started before it can be awaited. Otherwise it will never return
dataTask.Start();
DataTable table = await dataTask;

//Now we can perform operations on the Task result, as if we're executing code after the async operation completed
listBoxControl.DataContext = table;
StopStoryboard();
HideLoaderControl();

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.

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.

What exactly happens when you call an async method without the await keyword?

Then my periodic job and PutRecordBatchAsync are processed concurrently?

Using Task API you can ensure that they are executed concurrently (using Thread pool), but you need to understand the difference between in memory concurrent operations Vs IO based concurrency.

While In memory concurrency does benefit using Tasks, IO call once executed doesn't need thread at all, as it relies on hardware concurrency, if it ever use the thread, all that it would do it wait for the IO call to return, thus wasting the precious system resources and reducing system scalability

You case is that IO based concurrency, as you call a remote / network based API, how does async-await helps here ?

Well true Async operation will free up the thread context, on windows it would use IO completion port (queuing mechanism) to execute the Async call, while the calling thread is used to dispatch other similar calls, it would just need thread context on return of the IO call for serving the response and for that too, if its not a UI call, then use ConfigureAwait(false), so that any thread context can be used to deliver the response.

What if you don't use await with async ?

The call meant to be Asynchronous becomes Synchronous and would immediately impact the system scalability, as threads are now blocked, even worse for a long running IO operations. Have you seen how JavaScript frameworks always make a AJAX (Async) call to the server API, thus much more work is possible W/o blocking the Browser threads.

In general for In memory processing you would create certain number of Tasks and process them using Task.WaitAll or Parallel.ForEach for a collection, for Async processing, ideally recommendation is not to have a Task.Run anywhere, its preferred to have to Async from the entry point, like its possible in case of MVC, controllers can be async. Multiple calls are grouped together using Task.WhenAll representative Task and then awaited upon. even if you use Task.Run as in your code, then use async lambda to execute an asynchronous call

Summary :

Its mandatory to use await for asynchronous calls, else they async keyword is useless in that context and yes await will wait for the IO call to return before continuation is executed, though no thread is blocked in the process

Why do we need more than one `await` statement in a C# method?

await will wait until the operation is not executed. So you has 2 async operations, that's why you need to use await.

One await for each async operation (method).

So, you have 3 async methods. You can call it without await, but it will crash. When you call it without await, it will start to execute in another thread, and thread where SeedAsync is executing, will not wait until InsertAsync is executed. It will start second InsertAsync at the same time

So, in your case, you can insert values without await. It will work. But in common case it's better to use await. Because often order of operations is important. await is allow to control the order of operations

Sometimes you need to run some tasks and then wait for all. Then you can use Task.WhenAll(t1,t2,t3)

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.

Using await versus Result

Calling the Result will block the current thread until the operation completes. The await returns to the caller and continues with the rest of the method when the async operation is completed.

C# asynchronous functions - does await immediately start a task on a new thread?

For this function:

public async Task<LanDeviceInfo> GetLanDBDataAsync(LanDeviceInfo device)
{
return GetLanDBData(device);
}

compiler should issue a warning: "this async method lacks 'await' operators and will run synchronously". Compiler will convert this method to something like this:

public Task<LanDeviceInfo> GetLanDBDataAsync(LanDeviceInfo device)
{
var result = GetLanDBData(device);
return Task.FromResult(result);
}

So indeed compiler generated a task and returned it, but not in a way you expected. The whole method runs synchronously on caller (UI) thread and so blocks it the same way as GetLanDBData does.

Task basically represents some work in progress (or even already completed, as shown above with Task.FromResult), with ability to check the status of said work, and being notified when work is completed (or failed). It doesn't necessary has any relation to threads.

await someTask very rougly means - IF someTask is not already completed - then execute the rest of the method some time later, when someTask actually completes. It doesn't start any new tasks, nor does it create any new threads.

Your working version:

public async Task<LanDeviceInfo> GetLanDBDataAsync(LanDeviceInfo device)
{
var deviceInfo = await Task.Run(() => GetLanDBData(device));
return deviceInfo;
}

very rougly means -

  1. create a task representing the whole operation inside GetLanDBDataAsync method. Let's name that taskResult.

  2. Queue GetLanDBData to be executed on thread pool (because that's what documentation of Task.Run says it does, not just because "it's a task"). Task returned from Task.Run represents this pending operation.

  3. Now, if task returned from Task.Run is not yet completed (it does not) - return our taskResult (representing whole operation) back to the caller.

  4. When some time later task returned from Task.Run completes - we execute the rest of the code. In this case, result of Task.Run is just forwarded to our taskResult, because the rest of the code is just return deviceInfo.

What does await do in this function?

It awaits the completion of the HTTP request. The code resumes (for iteration...) only after every single request is complete.

Your 2nd version works precisely because it doesn't await for each task to complete before initiating the following tasks, and only waits for all the tasks to complete after all have been started.

What async-await is useful for is allowing the calling function to continue doing other things while the asynchronous function is awaiting, as opposed to synchronous ("normal") functions that block the calling function until completion.



Related Topics



Leave a reply



Submit