多个任务完成后如何调用一个任务
How to call one task after completion of multiple tasks
我有列表任务,这些任务做一些不相关的工作。我需要的是显示消息框,以防所有任务都正确完成工作。我尝试了几种方法,但对我来说没有任何效果。最简单的方法是使用
Task continuation = Tasks.WhenAll(tasks);
continuation.ContinueWith(obj => {
show messagebox
});
但是所有任务的 ContinueWith 仍然是 运行s,而不仅仅是延续任务。我尝试设置取消令牌或使用符号,但同时任务 运行,所以它不起作用。
如有任何帮助,我将不胜感激。
ContinueWith still runs for all tasks, not just for continuation task.
这是不正确的。 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").
}
在非异步函数中使用任务和在异步函数中使用它是有区别的。
对您问题的简短回答不是使用 Task.WhenAll,而是使用 Task.WaitAll。一旦所有任务完成,此功能 returns。之后你可以继续下一条语句,显示消息框
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(...)
}
Problem: your UI is not responsive while waiting for the tasks to finished
保持 UI 响应的一种简单方法是使用异步 - 等待。 Async-await 使您的程序保持响应,因为只要程序必须等待很长时间才能完成,控制权就会交还给您的主程序,它有时间做其他事情。
async-await 的好处在于代码看起来仍然是顺序的。您不必在 "when this task is finished do this other task".
的含义中使用 ContinueWith
要使用 async-await,您所要做的就是将您的事件处理程序声明为异步。在事件处理程序中,您可以调用任何其他异步函数。每当您需要等待任务的被调用函数的结果时。
您的代码如下所示:
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 在等待时响应。我为此所做的唯一事情是:
- 声明事件处理程序异步
- 使用 WhenAll 而不是 WaitAll。 WhenAll return 是一个(可等待的)任务
- 等待 WhenAll 完成。
为了能够使用 async-await,请记住以下几点:
- 如果您的函数必须等待很长时间,请将冗长的函数作为异步函数启动并等待它
- 为了能够使用 await,您的函数必须声明为 async
- 每个异步函数 returns Task 而不是 void 和 Task
<Tresult
> 而不是 TResult
- 有一个例外:异步事件处理程序 returns void
- await Task的return无效,await Task
<TResult
>的return为Tresult
Eric Lippert(感谢 Eric!)在
中解释了异步等待
假设早餐你必须烤面包和煮鸡蛋。有几种情况:
- 开始烤面包。等到它完成。开始煮鸡蛋,等它完成。同步处理。当你在等待面包烤好的时候,你不能做任何其他事情。
- 开始烤面包,烤面包的同时开始煮鸡蛋。当鸡蛋煮熟时,等到面包烤完。这称为异步,但不是并发。它是由主线程完成的,只要这个线程做了一些事情,主线程就不能做任何其他事情。但是在等待的时候它有时间做其他事情(例如泡茶)
- 雇用厨师烤面包和煮鸡蛋。等到两者都完成。异步并发:工作由不同的线程完成。这是最昂贵的,因为您必须启动新线程。
我有列表任务,这些任务做一些不相关的工作。我需要的是显示消息框,以防所有任务都正确完成工作。我尝试了几种方法,但对我来说没有任何效果。最简单的方法是使用
Task continuation = Tasks.WhenAll(tasks);
continuation.ContinueWith(obj => {
show messagebox
});
但是所有任务的 ContinueWith 仍然是 运行s,而不仅仅是延续任务。我尝试设置取消令牌或使用符号,但同时任务 运行,所以它不起作用。
如有任何帮助,我将不胜感激。
ContinueWith still runs for all tasks, not just for continuation task.
这是不正确的。 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").
}
在非异步函数中使用任务和在异步函数中使用它是有区别的。
对您问题的简短回答不是使用 Task.WhenAll,而是使用 Task.WaitAll。一旦所有任务完成,此功能 returns。之后你可以继续下一条语句,显示消息框
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(...)
}
Problem: your UI is not responsive while waiting for the tasks to finished
保持 UI 响应的一种简单方法是使用异步 - 等待。 Async-await 使您的程序保持响应,因为只要程序必须等待很长时间才能完成,控制权就会交还给您的主程序,它有时间做其他事情。
async-await 的好处在于代码看起来仍然是顺序的。您不必在 "when this task is finished do this other task".
的含义中使用 ContinueWith要使用 async-await,您所要做的就是将您的事件处理程序声明为异步。在事件处理程序中,您可以调用任何其他异步函数。每当您需要等待任务的被调用函数的结果时。
您的代码如下所示:
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 在等待时响应。我为此所做的唯一事情是:
- 声明事件处理程序异步
- 使用 WhenAll 而不是 WaitAll。 WhenAll return 是一个(可等待的)任务
- 等待 WhenAll 完成。
为了能够使用 async-await,请记住以下几点:
- 如果您的函数必须等待很长时间,请将冗长的函数作为异步函数启动并等待它
- 为了能够使用 await,您的函数必须声明为 async
- 每个异步函数 returns Task 而不是 void 和 Task
<Tresult
> 而不是 TResult - 有一个例外:异步事件处理程序 returns void
- await Task的return无效,await Task
<TResult
>的return为Tresult
Eric Lippert(感谢 Eric!)在
假设早餐你必须烤面包和煮鸡蛋。有几种情况:
- 开始烤面包。等到它完成。开始煮鸡蛋,等它完成。同步处理。当你在等待面包烤好的时候,你不能做任何其他事情。
- 开始烤面包,烤面包的同时开始煮鸡蛋。当鸡蛋煮熟时,等到面包烤完。这称为异步,但不是并发。它是由主线程完成的,只要这个线程做了一些事情,主线程就不能做任何其他事情。但是在等待的时候它有时间做其他事情(例如泡茶)
- 雇用厨师烤面包和煮鸡蛋。等到两者都完成。异步并发:工作由不同的线程完成。这是最昂贵的,因为您必须启动新线程。