如何在完成多个任务后调用一个任务

时间:2015-10-26 13:37:53

标签: c# task-parallel-library task

我有List任务,这些任务做了一些无关紧要的工作。我需要的是显示消息框,以防所有任务正常工作。我尝试了几种方法,但没有任何方法适合我。最简单的方法是使用

Task continuation = Tasks.WhenAll(tasks);
continuation.ContinueWith(obj => {
    show messagebox
});

但是ContinueWith仍然可以运行所有任务,而不仅仅是继续任务。我尝试设置取消令牌或使用签名,但任务同时运行,因此它不起作用。

我将不胜感激任何帮助。

2 个答案:

答案 0 :(得分:3)

  

ContinueWith仍然可以运行所有任务,而不仅仅是继续任务。

这是不正确的。当所有任务完成执行时,ContinueWith将运行一次。你可以很容易地模拟这个:

var tasks = new[] { Task.Delay(1000), Task.Delay(2000), Task.Delay(500) };
Task.WhenAll(tasks).ContinueWith(x => Console.WriteLine("Finished"));
Console.Read();

您只能看到“完成”一次打印。

如果可以,我肯定更愿意使用await而不是附加续篇:

public async Task FooAsync()
{
    var tasks = new[] { Task.Delay(1000), Task.Delay(2000), Task.Delay(500) };
    await Task.WhenAll(tasks);
    Console.WriteLine("Done").
}

答案 1 :(得分:2)

在非同步函数中使用Tasks并在异步函数中使用它之间存在差异。

简短回答您的问题不是使用Task.WhenAll,而是使用Task.WaitAll。所有任务完成后,此函数立即返回。之后,您可以继续下一个语句,显示消息框

private void OnButton1_clicked(object sender, ...)
{
    Task task1 = StartTask1(...);
    Task task2 = StartTask2(...);
    // do other things, after a while wait until all tasks are finished
    Task.WaitAll(new Task[] {task1, task2};
    MessageBox.Show(...)
 }
  

问题:在等待任务完成时,您的UI没有响应

保持UI响应的简单方法是使用async - await。 Async-await使您的程序保持响应,因为无论何时程序必须等待很长时间才能完成,控制权将返回给您的主程序,该程序有时间做其他事情。

async-await的好处是代码看起来仍然是顺序的。你不必在&#34的意义上使用ContinueWith;当这个任务完成时,做另外的任务"。

要使用async-await所需要做的就是将事件处理程序声明为异步。在eventhandler中,您可以调用任何其他异步函数。无论何时需要被调用函数的结果,都需要等待任务。

您的代码如下所示:

private async void OnButton1_clicked(object sender, ...)
{
    Task task1 = StartTask1(...);
    Task task2 = StartTask2(...);
    // while the tasks are being performed do other things,
    // after a while wait until all tasks are finished
    await Task.WhenAll(new Task[] {task1, task2};
    MessageBox.Show(...)
 }

此代码确保在等待您的UI时具有响应性。我做的唯一事情是:

  1. 声明事件处理程序async
  2. 使用WhenAll而不是WaitAll。 WhenAll返回(等待)任务
  3. 等待WhenAll完成。
  4. 为了能够使用async-await,请记住以下几点:

    • 如果你的函数需要等待很长时间,那么就像async函数一样启动冗长并等待它
    • 为了能够使用await,您的函数必须声明为async
    • 每个异步函数都返回Task而不是void和Task <Tresult&gt;而不是TResult
    • 有一个例外:异步事件处理程序返回void
    • 等待任务的返回无效,等待任务<TResult&gt;的返回是Tresult

    Eric Lippert(感谢Eric!)在Stackoverflow - async/await - Is this understanding correct?

    中解释async-await如下

    假设早餐你必须吐司面包和煮鸡蛋。它有几种情况:

    1. 开始烘烤面包。等到它完成。开始煮鸡蛋,等到它完成。同步处理。当你在等待面包烤面包时,你无法做任何其他事情。
    2. 开始烘烤面包,而面包正在烘烤开始煮鸡蛋。当鸡蛋煮熟时,等到面包完成烘烤。这称为异步,但不是并发。它由主线程完成,只要这个线程执行某些操作,主线程就无法执行任何其他操作。但是在它等待的时候,它有时间做其他的事情(例如喝茶)
    3. 雇用厨师烤面包,煮鸡蛋。等到两个都完成了。异步和并发:工作由不同的线程完成。这是最昂贵的,因为你必须开始新的线程。