如果我等待一个已经在运行或正在运行的任务会发生什么

本文关键字:运行 什么 任务 等待 一个 如果 | 更新日期: 2023-09-27 18:11:26

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

await _task;
我想知道当我写这段代码时会发生什么:
await _task;
await _task;

它会执行任务两次吗?还是因为已经运行而抛出异常?

如果我等待一个已经在运行或正在运行的任务会发生什么

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

No和No。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设置结果,这样您实际上可以同步获得值。

我拼凑了这个快速测试:

var i = 0;
var task = Task.Run(() => { i++; Console.WriteLine(i); return i; });
var x = await task;
var y = await task;
Console.WriteLine(x);
Console.WriteLine(y);

它写道:

1
1
1

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