Wait for a task (or tasks) to reach certain milestone, the async/await way

柔情痞子 提交于 2021-01-28 02:01:41

问题


There are tons of examples of how to wait for a thread to exit, but sometimes i need to wait just until several threads are "ready" or have reached certain milestone.

After reading: What's the proper way to wait for a .NET thread to start up?

and http://www.albahari.com/threading/

If i have understood correctly:

Wait for one Child Task to be ready:

//Main Method
var wh = new AutoResetEvent(false);
Task childTask = Task.Run(() => ChildTask(wh);
wh.WaitOne();

//Child
private void ChildTask(Barrier barrier){
//do what is needed to be done before main thread continues...
wh.Set();

}

Wait for several Childs to be ready:

//Main Method
var barrier = new Barrier(N+1);
Task childTask = Task.Run(() => ChildTask1(barrier);
Task childTask = Task.Run(() => ChildTask2(barrier);
...
Task childTask = Task.Run(() => ChildTaskN(barrier);

barrier.SignalAndWait(); //When all childs signal "ready" i will continue
OnMyEvent(); //for example, trigger an event

//Every Child
private void Child_i(Barrier barrier){
mainTask.MyEvent += MyEventHandler; //complete subscription before going any further
//do what is needed to be done before main thread continues...
barrier.SignalAndWait();

}

(Please feel free to add or suggest another good patterns)

So my question is: Is posible to use the async/await pattern to achieve the same?

Are there any advantages/disadvantages by using this new pattern?


回答1:


You can use await Task.WhenAll or Task.WaitAll to wait for your tasks to finish. If you want to wait for a task to reach a certain milestone, you can split it into 2 tasks and use ContinueWith, for example:

var task1 = Task.Run(() => Task1Part1());
task1.ContinueWith(t => Task1Part2(t.Result));
var task2 = Task.Run(() => Task2Part1());
task2.ContinueWith(t => Task2Part2(t.Result));

await Task.WhenAll(task1, task2);



回答2:


Refactoring your example, you can achieve the same result without having to use a Barrier or AutoResetEvent etc:

Task.WaitAll(
    Task.Run(() => ChildTask1()),
    Task.Run(() => ChildTask2()),
    Task.Run(() => ChildTask3()));

Or slightly cleaner

Parallel.Invoke(
    () => ChildTask1(),
    () => ChildTask2(),
    () => ChildTask3());

The issue with these methods is that they will still block the foreground thread until all the child tasks have completed. If you want to use the async await pattern then your child tasks will need to be asynchronous and the context from which you call them would also be asynchronous. The result could be something like

public async Task PerformChildTasksAsync()
{
    ...

    await Task.WhenAll(
        ChildTask1Async(),
        ChildTask2Async(),
        ChildTask3Async());

    ...
}


来源:https://stackoverflow.com/questions/32748328/wait-for-a-task-or-tasks-to-reach-certain-milestone-the-async-await-way

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!