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

本文关键字:任务 调用 一个 | 更新日期: 2023-09-27 18:19:20

我有一个任务列表,这些任务做一些不相关的工作。我需要的是显示消息框,以防所有的任务都正确地完成了工作。我尝试了几种方法,但没有一种对我有效。最简单的方法是使用

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

但是ContinueWith仍然运行所有任务,而不仅仅是continuation任务。我试图设置取消令牌或使用符号,但任务同时运行,所以它不起作用。

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

ContinueWith仍然对所有任务运行,而不仅仅是continuation任务。

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

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

你只会看到"Finished"打印一次。

如果可以,我当然更喜欢使用await而不是附加一个延续:

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

在非异步函数中使用Tasks和在异步函数中使用Tasks是有区别的。

对你的问题简短而简单的回答是不要使用Task。而不是使用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的好处是代码看起来仍然是顺序的。你不必在"当这个任务完成后再做另一个任务"的意思中使用ContinueWith。

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

你的代码看起来像这样:

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完成。

要能够使用async-await,请记住以下几点:

  • 如果你的函数需要等待一些很长的时间,把它作为一个异步函数启动,然后等待它
  • 为了能够使用await,你的函数必须声明为async
  • 每个异步函数返回Task而不是void和Task <Tresult>而不是result
  • 有一个例外:异步事件处理程序返回void
  • 等待任务返回无效,等待任务<TResult>返回result

Eric Lippert(谢谢Eric!)在Stackoverflow - async/await -这种理解正确吗?

假设早餐你必须烤面包和煮鸡蛋。有几个场景:

    开始烤面包。等到它完成。开始煮鸡蛋,等到煮熟。同步处理。在你等待面包烤熟的时候,你不能做任何其他事情。
  1. 开始烤面包,在烤面包时开始煮鸡蛋。鸡蛋煮熟后,等面包烤好。这被称为异步,但不是并发。它是由主线程完成的,只要这个线程做了一些事情,主线程就不能做任何其他事情。但是当它等待的时候,它有时间做其他事情(比如泡茶)
  2. 雇佣厨师烤面包和煮鸡蛋。等到两者都完成。异步和并发:工作由不同的线程完成。这是最昂贵的,因为你必须启动新的线程。