Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what happens if I await a task that is already running or ran?

Tags:

There is a Task variable and lets say the task is running right now.. by executing the following line.

await _task; 

I was wondering what happens when I write this code:

await _task; await _task; 

would it execute the task twice ? Or throw an exception because it has already run ?

like image 830
Bilal Fazlani Avatar asked Sep 07 '15 08:09

Bilal Fazlani


1 Answers

would it execute the task twice ? Or throw an exception because it has already run ?

No and no. The only thing await does is call Task.GetAwaiter, it does not cause anything to run. If the task already ran to completion, it will either extract the value if it is a Task<T>, or run synchronously to the next line if it is a Task, since there is an optimization for already completed tasks.

A simple demo:

async Task Main() {     var foo = FooAsync();     await foo;     await foo;      var bar = BarAsync();     var firstResult = await bar;     var secondResult = await bar;      Console.WriteLine(firstResult);     Console.WriteLine(secondResult); }  public async Task FooAsync() {     await Task.Delay(1); }  public async Task<int> BarAsync() {     await Task.Delay(1);     return 1; } 

If you drill down to the state machine itself, you'll see this:

this.<foo>5__1 = this.<>4__this.FooAsync(); taskAwaiter = this.<foo>5__1.GetAwaiter(); if (!taskAwaiter.IsCompleted) {     this.<>1__state = 0;     this.<>u__1 = taskAwaiter;     M.<FooBar>d__0 <FooBar>d__ = this;     this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter, M.<FooBar>d__0>                                                     (ref taskAwaiter, ref <FooBar>d__);     return; } 

This optimization first checks the completion of the task. If the task isn't complete, it will call UnsafeOnCompleted which will register the continuation. If it is complete, it breaks the switch and goes to:

this.<>1__state = -2; this.<>t__builder.SetResult(); 

Which sets the result for the underlying Task, and that way you actually get the value synchronously.

like image 124
Yuval Itzchakov Avatar answered Sep 20 '22 14:09

Yuval Itzchakov