Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET async\await fundamentals

After playing with .NET 4.5 async\await framework I have a question.

Let's look at this program (the msdn example):

    async Task<int> AccessTheWebAsync()
    {
        HttpClient client = new HttpClient();

        Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

        DoIndependentWork();

        string urlContents = await getStringTask;

        return urlContents.Length;
    }


    void DoIndependentWork()
    {
        resultsTextBox.Text += "Working . . . . . . .\r\n";
    }

The program will run in this order:

  1. new HttpClient.
  2. GetStringAsync invoke synchronously.
  3. In some point, GetStringAsync calls await and the control return to AccessTheWebAsync.
  4. DoIndependentWork invoked.
  5. The program waits the string to be returned (blocks if the operation didn't complete).
  6. return the length of the urlContent.

One thing that took me a while to understand is that the method GetStringAsync runs synchronously despite its name (the name convention is really misleading).

In oreder to run the method asynchronously, we need to use Task.Run or Task.Factory.StartNew explicitly.

But the real question is, if we have independent work, why not do it right away rather then waiting the await to be called from GetStringAsync? (In other words, why async methods doesn't run asynchronously by definition?)

EDIT: I'll rephrase the second and third operations:

(2) GetStringAsync start synchronously.

(3) In some point, GetStringAsync calls await and the thread forks, the control return to AccessTheWebAsync.

like image 405
TheTufik Avatar asked Oct 19 '13 00:10

TheTufik


People also ask

What is async await in asp net?

The async and await keywordsAn asynchronous method is one that is marked with the async keyword in the method signature. It can contain one or more await statements. It should be noted that await is a unary operator — the operand to await is the name of the method that needs to be awaited.

How does .NET async await work?

The async keyword turns a method into an async method, which allows you to use the await keyword in its body. When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete. await can only be used inside an async method.

What does await do in async C#?

The await operator suspends evaluation of the enclosing async method until the asynchronous operation represented by its operand completes. When the asynchronous operation completes, the await operator returns the result of the operation, if any.

What is the use of async and await in .NET core?

The async and await keywords in C# are the heart of async programming. By using those two keywords, you can use resources in . NET Framework, . NET Core, or the Windows Runtime to create an asynchronous method almost as easily as you create a synchronous method.


2 Answers

One thing that took me a while to understand is that the method GetStringAsync runs synchronously despite its name (the name convention is really misleading).

That is incorrect. GetStringAsync returns a Task<string>. It will return immediately, which means DoIndependentWork will (potentially) run before the download has completed. The await operator will asynchronously wait until the Task<T> returned by GetStringAsync is done.

But the real question is, if we have independent work, why not do it right away rather then waiting the await to be called from GetStringAsync? (In other words, why async methods doesn't run asynchronously by definition?)

The actual "work" of the asynchronous methods is running after the method has returned. The Task that's returned will (normally) be in a state that's not completed, which means the method is still running asynchronously. You can check Task.IsCompleted to verify.

Try this:

Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
Debug.WriteLine("Completed? {0}", getStringTask.IsCompleted); // Will likely print false
DoIndependentWork();
string urlContents = await getStringTask;
Debug.WriteLine("Completed now? {0}", getStringTask.IsCompleted); // Will always print true
like image 197
Reed Copsey Avatar answered Sep 16 '22 23:09

Reed Copsey


Each async method is split into segments on each await. Each segment will become a state on a compiler generated state machine.

Each await instruction works on an awaitable for which a Task is the most common case.

Each state/segment will be executed synchronously until the where the received awaitable is checked if it is already completed.

If the awaitable is completed, it execution will continue on the next state.

If the awaitable is not completed and there isn't a current SynchronizationContext, the execution will be blocked until the the awaitable is completed at which time the execution of the next state will be started.

If a current SynchronizationContext exists, the execution will return to the caller and when the awaitable is completed the continuation to the next state will be posted to the captured SynchronizationContext.

like image 30
Paulo Morgado Avatar answered Sep 20 '22 23:09

Paulo Morgado