skip to Main Content

I am new to async/await and I can not wrap my head around the thread creation.

My queries are:-

  1. Does async function without await creates a new thread to cater getData() as Main thread will not be blocked?
  2. What is Task as a return type doing here? Does it help with any thread creation?
  3. The result of this code is 1,2,ended,3 (Why is 2 printed before ended?)

Here is my code:

public class Class1
    {
        public async Task getValue()
        {

            Console.WriteLine("1");
            var str = getData();
            Console.WriteLine("ended");
            Console.ReadKey();

        }

        private async Task<string> getData()
        {
            Console.WriteLine("2");
            for (long i = 0; i < 100000000000000; i++)
            {
                continue;
            }

            Console.WriteLine("3");

            return "ss";
        }
}

Some forums said that Task is responsible for State management only and no new threads are being created.
But those questions are still in my head.

Please help

2

Answers


  1. Marking method as async does not actually makes it magically asynchronous, it still is a synchronous one unless it does something "truly async" (usually it is an awaited call to another "truly async" method). Everything before first await on "truly async" call will be executed synchronously.

    Since your method is not actually an async one it will block current thread until it is completed. If you want to return control to the calling method you can add call like await Task.Delay(...):

    private async Task<string> getData()
    {
        await Task.Delay(1000);
        Console.WriteLine("2");
        // ...
    }
    

    Which should result in the expected behavior (i.e. 2 printed after ended).

    Does async function without await creates a new thread to cater getData() as Main thread will not be blocked?

    No, it does not.

    What is Task as a return type doing here? Does it help with any thread creation?

    It allows caller to await the getData call when needed. Task is basically a future/promise which represents a result of some computation which can finish in the future.

    I highly recommend to read about the topic more:

    Login or Signup to reply.
  2. According to Microsoft’s guidelines:

    An asynchronous method that is based on TAP can do a small amount of work synchronously, such as validating arguments and initiating the asynchronous operation, before it returns the resulting task. Synchronous work should be kept to the minimum so the asynchronous method can return quickly.

    Your getData asynchronous method violates this guideline by doing all the work synchronously, and returning a completed task. This can be easily verified:

    Debug.Assert(getData().IsCompleted == true);
    

    And most likely also:

    Debug.Assert(getData() == Task.CompletedTask);
    

    Some people would disagree that is OK to call the getData "asynchronous". They would call it synchronous, or fake asynchronous. The terminology that I prefer is that the getData is a method with asynchronous signature and synchronous implementation. To answer your questions directly:

    Does async function without await creates a new thread to cater getData() as Main thread will not be blocked?

    No, a new thread in not created. All code runs on the main thread of the console application.

    What is Task as a return type doing here? Does it help with any thread creation?

    The Task represents the completion of the asynchronous method. In case an exception is thrown inside the async method, the information about the exception will be stored inside this Task. Invoking the getData will never throw synchronously the exception. In order to expose the exception, you’ll have to Wait or await the resulting Task. The Task doesn’t create any thread by itself, no.

    Why is 2 printed before ended?

    Because all code runs synchronously on the same thread from start to finish.

    The purpose of the async/await technology is to enable the composition of derived asynchronous methods that are based on primitive asynchronous methods. For example if you have a built-in asynchronous API like the HttpClient.GetStringAsync, you can easily use it to author an asynchronous method that fetches some information from the internet based on specific parameters, and returns a deserialized representation of the data. The data will be returned on a thread that is decided by the implementation of the primitive API that you are calling. When the Task completes, the await continuation will run on whatever thread was selected by the HttpClient.GetStringAsync implementation. It’s not up to you to decide. What the caller of your API can do is to install a specialized SynchronizationContext on the current thread, that will cause a redirection from the thread selected by the HttpClient.GetStringAsync implementation to a thread selected by the SynchronizationContext implementation. Most UI frameworks (WinForms, WPF etc) install automatically their own specialized SynchronizationContext on the UI thread, so the developers don’t have to do anything special. You can learn more about this here:

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search