Task.WhenAll - 不等待子任务完成

6

关于TPL我有一些问题。 正如你所看到的,我创建了2个简单的任务并将它们添加到列表中。 问题(预期行为)是,在WorkMethodAsync中点击“await”后,任务立即返回,因此使Task.WhenAll无用。 有没有办法等待子任务完成? 我找到的唯一解决方法是伪造WorkMethodAsync成同步。

private async void button1_Click(object sender, EventArgs e)
{
    Tasks = new List<Task>();
    var myTask1 = Task.Factory.StartNew(async () => await WorkMethodAsync(), CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
    var myTask2 = Task.Factory.StartNew(async () => await WorkMethodAsync(), CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);

    Tasks.Add(myTask1);
    Tasks.Add(myTask2);

    await Task.WhenAll(Tasks.ToArray());
}
private async Task WorkMethodAsync()
{
    while (true)
    {
        await Task.Delay(10000);
    }
    return;
}

@AsadSaeeduddin 这是一个事件处理程序。在这种情况下(仅限于此种情况),使用 async void 是完全可以的。 - i3arnon
@i3arnon 是的,我知道这个问题。但是当你返回void时,调用方法不会等待Task.WhenAll的结果,这就是我认为可能存在的问题。我阅读了你的答案并意识到问题在于你得到了一个Task<Task>,它立即完成了。 - Asad Saeeduddin
1个回答

10

问题在于您正在使用Task.Factory.StartNew而不是Task.Run

StartNew是在async-await之前构建的,因此对其支持不太好。在这种情况下,由于您的委托返回一个任务并且StartNew创建了一个任务,因此返回值为Task<Task>>。您可以使用Unwrap来获取表示整个异步操作的任务:

Task<Task> myTask1 = Task.Factory.StartNew(async () => await WorkMethodAsync(), CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
Task<Task> myTask2 = Task.Factory.StartNew(async () => await WorkMethodAsync(), CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);

Tasks.Add(myTask1.Unwrap());
Tasks.Add(myTask2.Unwrap());

然而,使用Task.Factory.StartNew没有理由,因为对于异步方法,TaskCreationOptions.LongRunning没有意义(更多信息请参见我的博客:LongRunning Is Useless For Task.Run With async-await),因此您可以直接使用Task.Run

var myTask1 = Task.Run(() => WorkMethodAsync());
var myTask2 = Task.Run(() => WorkMethodAsync());

1
非常感谢。我一定会查看你的博客!希望这能解决线程因某些原因过早退出的问题?! - matelras
  1. 不,它不会。
  2. 返回的任务已经在执行中。你可以说Unwrap阻塞等待它完成,但实际上并不是这样。
- i3arnon
很棒的答案。我有一个类似的问题,但是我仍然需要Task.Factory.StartNew,因为我在这里使用另一个TaskScheduler(具有有限并发性)。 - ygoe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接