Tim Andrews
Tim Andrews

Reputation: 847

Is there overhead when calling await on already split context?

EDIT: My question doesn't really make sense because I was misunderstanding how tasks work. I've marked stephen cleary's answer as accepted because it pointed me in the direction to learn my mistakes.

I often see code like this:

public async Task DoSomething(){
     await DoSomethingElse();
     await DoSoManyThings();
     await DoEverything();
}

Now the way I see this is that the first await starts a second thread and returns control to the calling thread. When the await finishes, the second await is called. Now this is where i might be confused. The second await splits context / creates new thread and the other thread disappears(returns to caller). Is there an overhead to this? If so, how much? IS it better to have my code as follows, to avoid creating new thread for no reason:

public async Task DoSomething(){
     await DoSomethingElse();
      DoSoManyThings();
      DoEverything();
}

Here is a full code example showing what I mean, as requested. The loop is there to ensure the awaited code isn't instantly completed. Output is identical for both test functions.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestApplication
{
    public class Program
    {
        static void Main(string[] args)
        {
            Program test = new Program();
            Task firstTest = test.StartMultipleAwaitTest();
            firstTest.Wait();
            test.StartSingleAwaitTest();
            Console.ReadLine();
        }

        public async Task StartSingleAwaitTest() 
        {
            Console.WriteLine("\nStarting second test");
            await FirstTask();
            SecondTask();
            ThirdTask();
            Console.WriteLine("End");
        }

        public async Task StartMultipleAwaitTest() 
        {
            Console.WriteLine("Start");
            await FirstTask();
            await SecondTask();
            await ThirdTask();
            Console.WriteLine("End");
        }

        public async Task FirstTask() 
        {
            Console.WriteLine("Start First task");
            for (int i = 0; i < 10000000; i++) { }
            Console.WriteLine("End Firt task");
        }

        public async Task SecondTask()
        {
            Console.WriteLine("Start Second task");
            for (int i = 0; i < 10000000; i++) { }
            Console.WriteLine("End Second task");
        }

        public async Task ThirdTask()
        {
            Console.WriteLine("Start Third task");
            for (int i = 0; i < 10000000; i++) { }
            Console.WriteLine("End Third task");
        }
    }
}

Upvotes: 1

Views: 304

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456607

the first await starts a second thread and returns control to the calling thread.

No. await most emphatically does not start a second thread. I have a blog post describing what await does do in detail.

Output is identical for both test functions.

The reason the output is identical is because in both cases, all functions run synchronously. Pay attention to your compiler warnings; in this case, the compiler will give you warnings on your FirstTask method (and friends), stating that these methods will run synchronously.

What's actually happening in the StartMultipleAwaitTest test is that the methods have run to completion before the await even examines the Task. Similarly, in the StartSingleAwaitTest test, the methods also synchronously run to completion before returning to StartSingleAwaitTest.

A more real-world test (i.e., doing asynchronous work in an asynchronous method) will give you more real-world results:

public async Task FirstTask() 
{
  Console.WriteLine("Start First task");
  await Task.Delay(TimeSpan.FromSeconds(2));
  Console.WriteLine("End Firt task");
}

public async Task SecondTask()
{
  Console.WriteLine("Start Second task");
  await Task.Delay(TimeSpan.FromSeconds(3));
  Console.WriteLine("End Second task");
}

public async Task ThirdTask()
{
  Console.WriteLine("Start Third task");
  await Task.Delay(TimeSpan.FromSeconds(2));
  Console.WriteLine("End Third task");
}

Upvotes: 3

Related Questions