【问题标题】:Task.WhenAll - not waiting for child tasks to finishTask.WhenAll - 不等待子任务完成
【发布时间】:2016-01-30 07:45:35
【问题描述】:

我有一些关于 TPL 的问题。 如您所见,我正在创建 2 个简单任务并将它们添加到列表中。 问题(预期行为)是任务在点击WorkMethodAsync 中的“等待”后立即返回,因此使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 是的,我知道这一点。但是,当您返回 void 时,调用方法不会等待 Task.WhenAll 的结果,这就是我认为可能存在的问题。我阅读了您的回答并意识到问题是您收到了一个Task&lt;Task&gt;,它正在立即完成。

标签: c# .net multithreading async-await task-parallel-library


【解决方案1】:

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

StartNew 是在 async-await 之前构建的,因此不能很好地支持它。在这种情况下,由于您的委托返回了一个任务并且StartNew 创建了一个任务,因此返回值为Task&lt;Task&gt;&gt;。您可以使用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());

【讨论】:

  • 非常感谢。我一定会检查你的博客!我希望这能解决由于某种原因线程过早退出的问题?!​​
  • @PhillipScottGivens 1. 不,它没有。 2. 返回的任务已经在执行。你可以说Unwrap 阻塞等待它完成,但它没有。
  • 很好的答案。我遇到了类似的问题,但我仍然需要Task.Factory.StartNew,因为我在这里使用了另一个TaskScheduler(并发受限)。
猜你喜欢
  • 2021-07-17
  • 2013-12-18
  • 2012-11-06
  • 1970-01-01
  • 1970-01-01
  • 2015-11-16
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多