完成多个任务后如何调用一个任务 [英] How to call one task after completion of multiple tasks

查看:74
本文介绍了完成多个任务后如何调用一个任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Task continuation = Tasks.WhenAll(tasks);continuation.ContinueWith(obj => {显示消息框});

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

我将不胜感激.

解决方案

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

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

private void OnButton1_clicked(object sender, ...){任务 task1 = StartTask1(...);任务 task2 = StartTask2(...);//做其他事情,稍等片刻,直到所有任务完成Task.WaitAll(new Task[] {task1, task2};MessageBox.Show(...)}

<块引用>

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

保持 UI 响应的一种简单方法是使用 async - await.Async-await 使您的程序保持响应,因为每当程序必须等待很长时间才能完成时,控制权就会交还给您的主程序,它有时间做其他事情.

async-await 的好处是代码看起来仍然是有序的.您不必使用 ContinueWith 的意思是当此任务完成后执行其他任务".

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

您的代码如下所示:

private async void OnButton1_clicked(object sender, ...){任务 task1 = StartTask1(...);任务 task2 = StartTask2(...);//在执行任务的同时做其他事情,//稍等片刻,直到所有任务完成await Task.WhenAll(new Task[] {task1, task2};MessageBox.Show(...)}

此代码可确保在等待时您的 UI 具有响应性.我这样做的唯一目的是:

  1. 声明事件处理程序异步
  2. 使用 WhenAll 而不是 WaitAll.WhenAll 返回一个(等待的)任务
  3. 等待 WhenAll 完成.

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

  • 如果您的函数必须等待很长时间,请将其作为异步函数启动并等待它
  • 为了能够使用 await,您的函数必须声明为异步
  • 每个异步函数都返回 Task 而不是 void 和 Task> 而不是 TResult
  • 有一个例外:异步事件处理程序返回 void
  • await Task的返回是void,await Task>的返回是Tresult

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

假设早餐你必须烤面包和煮鸡蛋.有几种情况:

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

I have List tasks, these tasks do some irrelevant work. What I need is to show message box in case all the tasks did their work correctly. I tried few ways, but nothing worked properly for me. Simplest way could be use

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

but ContinueWith still runs for all tasks, not just for continuation task. I tried to set cancellation token or to use sign, but tasks run at same time, so it isn't working.

I will be grateful for any help.

解决方案

There is a difference between using Tasks in a non-async function and using it in an async function.

The short and easy answer to your question is not to use Task.WhenAll, but to use Task.WaitAll. This function returns as soon as all Tasks are finished. After that you can continue with the next statement, show the message box

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

An easy method to keep your UI responsive is using async - await. Async-await keeps your program responsive, because whenever if the procedure has to wait for something lengthy to finish, control is given back to your main program which has time to do other things.

The nice thing about async-await is that the code still looks sequential. You don't have to use ContinueWith in the meaning of "when this task is finished do this other task".

All you have to do to be able to use async-await is declare your event handler async. In the eventhandler you can call any other async function. Whenever you need the result of the called function you await for the task.

Your code would look like follows:

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(...)
 }

This code makes sure that while waiting your UI is responsive. The only things I did to do this were:

  1. declare the event handler async
  2. Use WhenAll instead of WaitAll. WhenAll returns an (awaitable) Task
  3. Await for WhenAll to complete.

To be able to use async-await keep the following in mind:

  • If your function has to wait for something lengthy, start the lengthy as an async function and await for it
  • To be able to use await, your function must be declared async
  • Every async function returns Task instead of void and Task<Tresult> instead of TResult
  • There is one exception: an async event handler returns void
  • The return of await Task is void, the return of await Task<TResult> is Tresult

Eric Lippert (thanx Eric!) explained async-await as follows in Stackoverflow - async/await - Is this understanding correct?

Suppose for breakfast you have to toast bread and cook eggs. There are several scenarios for it:

  1. Start toasting bread. Wait until it is finished. Start cooking eggs, wait until it is finished. Synchronous processing. While you are waiting for the bread to toast you can't do anything else.
  2. Start toasting bread, while the bread is being toasted start cooking eggs. when the eggs are cooked wait until the bread finished toasting. This is called Asynchronous, but not concurrent. It is done by the main thread and as long as this thread does something, the main thread can't do anything else. But while it is waiting it has time to do other things (make some tea for instance)
  3. Hire cooks to toast the bread and cook the eggs. Wait until both are finished. Asynchronous and concurrent: the work is done by different threads. This is the most expensive because you have to start new threads.

这篇关于完成多个任务后如何调用一个任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆