如果我等待已经运行或运行的任务会发生什么?

时间:2015-09-07 08:43:05

标签: c# .net asynchronous parallel-processing task-parallel-library

有一个Task变量,让我们说现在正在运行任务..通过执行以下行。

await _task;

我想知道写这段代码会发生什么:

await _task;
await _task;

它会执行两次任务吗?或抛出异常,因为它已经运行了?

2 个答案:

答案 0 :(得分:15)

  

它会执行两次任务吗?或抛出异常,因为它有   已经跑了?

不,不。 await唯一能做的就是调用Task.GetAwaiter,它不会导致任何运行。如果任务已经完成,它将提取值Task<T>,或者如果它是Task则同步运行到下一行,因为已完成任务的优化

一个简单的演示:

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;
}

如果您深入了解状态机本身,您会看到:

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;
}

此优化首先检查任务的完成情况。如果任务没有完成,它将调用UnsafeOnCompleted,这将注册继续。如果完成,则会中断switch并转到:

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

设置基础Task的结果,这样您实际上可以同步获得该值。

答案 1 :(得分:7)

我把这个快速测试汇总在一起:

1
1
1

它写道:

      function formatDate(date) {
      var hours = date.getHours();
      var minutes = date.getMinutes();
      var ampm = hours >= 12 ? 'pm' : 'am';
      hours = hours % 12;
      hours = hours ? hours : 12; // the hour '0' should be '12'
      hours = hours < 10 ? '0'+hours : hours;
      minutes = minutes < 10 ? '0'+minutes : minutes;
      var strTime = hours + ':' + minutes + ' ' + ampm;

      var Month = date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1) : date.getMonth()+1;
      var Date = date.getDate() < 10 ? '0'+date.getDate() : date.getDate();
      var strDate = Month + "/" + Date + "/" + date.getFullYear();
      return strDate + " " + strTime;
    }

所以,显然,任务只运行一次。