Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async programming control flow

Tags:

c#

async-await

I have been reading about c# async methods in the past 2 days and from what I understand, unlike in a thread (threadpool.queueuserworkitem()), a call to an async method does not return immediately and it only returns when the called method hits an await or complete(or exception)

Please see the following example.

public partial class MainWindow : Window
{
    // . . .
    private async void startButton_Click(object sender, RoutedEventArgs e)
    {
        // ONE
        Task<int> getLengthTask = AccessTheWebAsync();

        // FOUR
        int contentLength = await getLengthTask;

        // SIX
        resultsTextBox.Text +=
            String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
    }


    async Task<int> AccessTheWebAsync()
    {
        // TWO
        HttpClient client = new HttpClient();
        Task<string> getStringTask =
            client.GetStringAsync("http://msdn.microsoft.com");

        // THREE                 
        string urlContents = await getStringTask;

        // FIVE
        return urlContents.Length;
    }
} 

From what I gather, in the above code, AccessTheWebAsync() is called synchronously(i.e. control does not return immediately when it is called). But in the line named 'THREE', the runtime will return control.

My questions are:

  1. How does the runtime decide when to use the threadpool or when to run the task in the calling thread? (i.e. execute the code without returning control)

  2. At which points in the above code, new threads (or thread pool) will be used?

  3. If AccessTheWebAsync() did something computationally intensive, like running a loop with a zillion iterations, the control will only return to the caller when the loop is completed. Is that right?

  4. In an async function, is there a way to return the control immediately and then continue doing the work in say a background thread? (just like if we called threadpool.queueuserworkitem())

  5. Is calling an async method without an await in it (assume it s possible) same as calling a non async method?

like image 941
Amila Avatar asked Jun 07 '13 07:06

Amila


2 Answers

First something important: The runtime will only return to the caller on await if the task to await hasn't completed yet.

Question 1: I'll quote the MSDN here:

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.

Source

Question 2: Maybe in the implementation of GetStringAsync but we don't know that and we also don't have to know it. It's enough for us to know that GetStringAsync somehow gets its result without blocking our thread.

Question 3: If the loop is placed before the await keyword, yes.

Question 4: Quote from the same paragraph as before:

You can use Task.Run to move CPU-bound work to a background thread

You don't need the async and await keywords for this. Example:

private Task<int> DoSomethingAsync()
{
    return Task.Run(() =>
    {
        // Do CPU heavy calculation here. It will be executed in the thread pool.
        return 1 + 1;
    });
}

Question 5: I'll quote again

An async method typically contains one or more occurrences of an await operator, but the absence of await expressions doesn’t cause a compiler error. If an async method doesn’t use an await operator to mark a suspension point, the method executes as a synchronous method does, despite the async modifier. The compiler issues a warning for such methods.

Source (same page as before, just a different section)

like image 87
cremor Avatar answered Oct 20 '22 15:10

cremor


How does the runtime decide when to use the threadpool or when to run the task in the calling thread?

If there is a synchronization context and you don't explicitly specify you don't want to continue on the context (by using something like await task.ConfigureAwait(false)), then the method will resume on the captured context. In UI applications, that context is the UI thread, assuming the method is called from the UI thread.

At which points in the above code, new threads (or thread pool) will be used?

Nowhere. Unless you specify otherwise (see above), await resumes back on the captured context, which in your case is the UI thread.

If AccessTheWebAsync() did something computationally intensive, like running a loop with a zillion iterations, the control will only return to the caller when the loop is completed. Is that right?

Yes, assuming the loop was before the first “asynchronous” await. (await can also be “synchronous” if the awaited Task is already completed.)

In an async function, is there a way to return the control immediately and then continue doing the work in say a background thread?

You should use Task.Run() for that.

Is calling an async method without an await in it (assume it s possible) same as calling a non async method?

It is possible and the compiler will warn you that the method will execute completely synchronously.

like image 35
svick Avatar answered Oct 20 '22 13:10

svick