等待一个任务(或多个任务)达到某个里程碑,async/await 方式
Wait for a task (or tasks) to reach certain milestone, the async/await way
有很多关于如何等待线程退出的例子,但有时我需要等到几个线程 "ready" 或达到某个里程碑。
看完后:
What's the proper way to wait for a .NET thread to start up?
和
http://www.albahari.com/threading/
如果我没理解错的话:
等待一个子任务就绪:
//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();
}
等待多个 Childs 就绪:
//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();
}
(欢迎补充或推荐其他好的图案)
所以我的问题是:
是否可以使用 async/await 模式来实现相同的目的?
有没有advantages/disadvantages使用这个新模式?
您可以使用 await Task.WhenAll
或 Task.WaitAll
等待您的任务完成。
如果你想等待一个任务达到某个里程碑,你可以把它拆分成2个任务,然后使用ContinueWith
,例如:
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);
重构您的示例,无需使用 Barrier
或 AutoResetEvent
等即可获得相同的结果:
Task.WaitAll(
Task.Run(() => ChildTask1()),
Task.Run(() => ChildTask2()),
Task.Run(() => ChildTask3()));
或稍微清洁一些
Parallel.Invoke(
() => ChildTask1(),
() => ChildTask2(),
() => ChildTask3());
这些方法的问题是它们仍然会阻塞前台线程,直到所有子任务完成。如果您想使用异步等待模式,那么您的子任务将需要是异步的,并且您调用它们的上下文也将是异步的。结果可能类似于
public async Task PerformChildTasksAsync()
{
...
await Task.WhenAll(
ChildTask1Async(),
ChildTask2Async(),
ChildTask3Async());
...
}
有很多关于如何等待线程退出的例子,但有时我需要等到几个线程 "ready" 或达到某个里程碑。
看完后: What's the proper way to wait for a .NET thread to start up?
和 http://www.albahari.com/threading/
如果我没理解错的话:
等待一个子任务就绪:
//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();
}
等待多个 Childs 就绪:
//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();
}
(欢迎补充或推荐其他好的图案)
所以我的问题是: 是否可以使用 async/await 模式来实现相同的目的?
有没有advantages/disadvantages使用这个新模式?
您可以使用 await Task.WhenAll
或 Task.WaitAll
等待您的任务完成。
如果你想等待一个任务达到某个里程碑,你可以把它拆分成2个任务,然后使用ContinueWith
,例如:
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);
重构您的示例,无需使用 Barrier
或 AutoResetEvent
等即可获得相同的结果:
Task.WaitAll(
Task.Run(() => ChildTask1()),
Task.Run(() => ChildTask2()),
Task.Run(() => ChildTask3()));
或稍微清洁一些
Parallel.Invoke(
() => ChildTask1(),
() => ChildTask2(),
() => ChildTask3());
这些方法的问题是它们仍然会阻塞前台线程,直到所有子任务完成。如果您想使用异步等待模式,那么您的子任务将需要是异步的,并且您调用它们的上下文也将是异步的。结果可能类似于
public async Task PerformChildTasksAsync()
{
...
await Task.WhenAll(
ChildTask1Async(),
ChildTask2Async(),
ChildTask3Async());
...
}