Home > Back-end >  Async method runs synchronously unless Task is first declared as variable?
Async method runs synchronously unless Task is first declared as variable?

Time:07-22

I am trying to wrap my head around the proper way to call asynchronous tasks. Consider the following code:

var stopWatch = new Stopwatch();

// TEST 1 AWAITS THE ASYNC TASKS DIRECTLY
stopWatch.Start();
Console.WriteLine($"Test 1 Begin: {stopWatch.ElapsedMilliseconds}");
await Task1(stopWatch);
await Task2(stopWatch);
Console.WriteLine($"Test 1 End: {stopWatch.ElapsedMilliseconds}");


Console.WriteLine();
Console.WriteLine();
stopWatch.Restart();


// TEST 2 CREATES A LOCAL VARIABLE OF THE TASK THEN AWAITS THE LOCAL VARIABLE
Console.WriteLine($"Test 2 Begin: {stopWatch.ElapsedMilliseconds}");
var task1 = Task1(stopWatch);
var task2 = Task2(stopWatch);
await task1;
await task2;
Console.WriteLine($"Test 2 End: {stopWatch.ElapsedMilliseconds}");


async Task Task1(Stopwatch stopWatch)
{
    Console.WriteLine($"Task 1 Start: {stopWatch.ElapsedMilliseconds}");
    await Task.Delay(2000);
    Console.WriteLine($"Task 1 End: {stopWatch.ElapsedMilliseconds}");
}

async Task Task2(Stopwatch stopWatch)
{
    Console.WriteLine($"Task 2 Start: {stopWatch.ElapsedMilliseconds}");
    await Task.Delay(2000);
    Console.WriteLine($"Task 2 End: {stopWatch.ElapsedMilliseconds}");
}

TEST 1 total time: 4 seconds

TEST 2 total time: 2 seconds

Why is TEST 1 running synchronously and TEST 2 is running asynchronously?

CodePudding user response:

In Test 1 you await the first Task which runs to completion then you start the second Task.

In Test 2 you start both Tasks so when the first has run to completion the second is also either complete or really close to it so await takes no time or very little time.

Nothing is synchronous, the tasks are still executing asynchronously.

CodePudding user response:

You need to think about what is actually happening in two cases. I the first case If you look at the output that the log is

Task 1 Start:...
Task 2 Start:...
Task 1 End
Task 2 End

This is because the code in your method will run until the first await operator, then it will return a Task, then the second method runs and again return a task. When you do await on a task it's similar to calling task.ContinueWith(...) method on it. And because the two timers have started almost at the same time the timer will finish at the same time with the Task will be completed at the second call. So the total is ~2s. On the second call the output is

Task 1 Start:...
Task 1 End
Task 2 Start:...
Task 2 End

That is because it needed to await the first task before it started the second second task. Try reading this for more information. https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/

  • Related