等待手动创建的任务不考虑内部等待

Den*_*sel 1 c# task async-await

我在使用 async 和 await 时遇到了奇怪的行为。如果我尝试等待手动创建的任务 T1,它本身应该等待另一个任务 T2,即使任务 T2 仍在等待,任务 T1 已经运行完成。

为了说明这个问题,我写了一些代码。当我从此示例中运行“task1”时,输出为:

task1 运行完成更新...

当我运行“task2”时,输出总是:

正在更新... task2 运行完成

有没有人解释为什么第一个等待表达式不依赖于内部等待?

private void OnLoaded(object sender, RoutedEventArgs e)
{
    var task1 = new Task(async () => await UpdateAfterDelay());
    task1.Start();
    await task1;
    Console.WriteLine("task1 ran to completion");

    var task2 = Task.Run(async () => await UpdateAfterDelay());
    await task2;
    Console.WriteLine("task2 ran to completion");
}

private async Task UpdateAfterDelay()
{
    await Task.Delay(2000);
    Console.WriteLine("updating...");
}
Run Code Online (Sandbox Code Playgroud)

Gab*_*uci 5

丹尼尔有正确的想法。如果您查看 的构造函数Task,它们都只接受Action对象,它们本质上是void方法。这意味着您的匿名方法被解释为async void,即“即发即弃”(启动它,不要等待)。

如果您不使用匿名方法,这将变得更加清楚:

var task1 = new Task(UpdateAfterDelayTask); //this does not compile

var task2 = new Task(UpdateAfterDelayVoid); //this does

private async Task UpdateAfterDelayTask()
{
    await Task.Delay(2000);
}

private async void UpdateAfterDelayVoid()
{
    await Task.Delay(2000);
}
Run Code Online (Sandbox Code Playgroud)

task1分配抱怨,你给它的方法有错误的返回类型。

Task.Run但是,有一个重载,它接受 a Func<Task>(一个返回 a 的方法Task)。所以编译器检查你的匿名方法,看到它返回 a Task,并选择Func<Task>重载。该重载返回一个新的Task,它取决于Task您的匿名方法返回的

综上所述,也许您正在使用new TaskTask.Run没有共享是有原因的,但就现状而言,您实际上并不需要这样做。你可以这样做:

var task1 = UpdateAfterDelay();
// do something else
await task1;
Run Code Online (Sandbox Code Playgroud)

如果您没有“做其他事情”,那么您根本不需要该task1变量。只是await UpdateAfterDelay()

同样值得注意的是这篇文章解释了为什么你几乎从不需要使用new Task(),而这篇后面的文章(写在Task.Run出来之后)解释了为什么你几乎总是想使用Task.Run()(如果你甚至需要的话)。