Roman Marusyk
Roman Marusyk

Reputation: 24619

Different behavior async/await in almost the same methods

Let's say I have two async methods

public async static Task RunAsync1()
{
    await Task.Delay(2000);
    await Task.Delay(2000);
}

and

public async static Task RunAsync2()
{
    var t1 = Task.Delay(2000);
    var t2 = Task.Delay(2000);

    await t1;
    await t2;
}

Then I use it like

public static void M()
{
    RunAsync1().GetAwaiter().GetResult();
    RunAsync2().GetAwaiter().GetResult();
}

In a result the RunAsync1 will run 4sec but RunAsync2 only 2sec
Can anybody explain why? Methods are almost the same. What is the difference?

Upvotes: 23

Views: 1974

Answers (4)

Pablo notPicasso
Pablo notPicasso

Reputation: 3161

Just examine your code:

public async static Task RunAsync1()
{
    await Task.Delay(2000); // Start a delay task, and WAIT for it to finish
    await Task.Delay(2000); // Start a delay task, and WAIT for it to finish
}

So the second await Task.Delay(2000); is called after the first call is finished (after 2 seconds).

While the second method,

public async static Task RunAsync2()
{
    var t1 = Task.Delay(2000); // Start a task
    var t2 = Task.Delay(2000); // Start a task

    await t1; // Wait for task to finish
    await t2; // Wait for task to finish
}

So tasks t1, and t2 run at the same time.

If you change it to

public async static Task RunAsync3()
{
    var t1 = Task.Delay(2000); // Start a task
    await t1; // Wait for task to finish

    var t2 = Task.Delay(2000); // Start a task
    await t2; // Wait for task to finish
}

you would get the same results as in RunAsync1.

Upvotes: 14

Thaina Yu
Thaina Yu

Reputation: 1512

Whenever you start a Task. It already started when you created it, not when you called await.

If you create a task and put it in a variable, it might already finish when you await that. This is what happen to your second case. await just ensures that it must finish before continuing.

Upvotes: 5

Aron
Aron

Reputation: 15772

In the first case you are saying

public async static Task RunAsync1()
{
    var t1 = Task.Delay(2000);
    await t1;
    var t2 = await Task.Delay(2000);
    await t2;
}

Which equates to

  1. 0:00 Create a callback in 2 seconds 0:00
  2. 0:00 Wait until the callback has returned 0:02
  3. 0:02 Create a callback in 2 seconds 0:02
  4. 0:02 Wait until the callback has returned 0:04
  5. 0:04 return;

The second case is

public async static Task RunAsync2()
{
    var t1 = Task.Delay(2000);
    var t2 = Task.Delay(2000);

    await t1;
    await t2;
}
  1. 0:00 Create callbacks in 2 seconds 0:00
  2. 0:00 Create callbacks in 2 seconds 0:00
  3. 0:00 Wait for first callback 0:02
  4. 0:02 Wait for the second callback 0:02
  5. 0:02 return

In other words, in the first one you are doing sequential asynchronous programming, and the second is parallel asynchronous programming.

Upvotes: 6

Evk
Evk

Reputation: 101643

In the second method 2 tasks are started at the same time. They will both finish in 2 seconds (as they are running in parallel). In the first method you first run one method (2 seconds), wait for it to complete, then start the second one (2 more seconds). The key point here is Task.Delay(..) starts right when you call it, not when you await it.

To clarify more, first method:

var t1 = Task.Delay(2000); // this task is running now
await t1; // returns 2 seconds later
var t2 = Task.Delay(2000); // this task is running now
await t2; // returns 2 more seconds later

Second method:

var t1 = Task.Delay(2000); 
var t2 = Task.Delay(2000); // both are running now

await t1; // returns in about 2 seconds
await t2; // returns almost immediately, because t2 is already running for 2 seconds

Upvotes: 58

Related Questions