【问题标题】:Wait for a task (or tasks) to reach certain milestone, the async/await way等待一个(或多个)任务达到某个里程碑,异步/等待方式
【发布时间】:2015-09-23 19:51:19
【问题描述】:

关于如何等待线程退出的例子有很多,但有时我需要等到几个线程“准备好”或达到某个里程碑。

阅读后: 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();

}

等待几个孩子准备好

//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 模式来实现相同的效果?

使用这种新模式有什么优点/缺点吗?

【问题讨论】:

  • await Task.WhenAll(tasks)
  • 你可以使用 Stephen Toub 的AsyncAutoResetEvent,它是为异步使用而设计的。
  • 我去看看,谢谢你的建议。

标签: c# multithreading asynchronous synchronization async-await


【解决方案1】:

您可以使用await Task.WhenAllTask.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);

【讨论】:

  • 这样,任务在达到里程碑的第二秒就可以继续。有了屏障,所有任务都必须等待“慢加入者”。分而治之:)
【解决方案2】:

重构您的示例,您无需使用BarrierAutoResetEvent 等即可获得相同的结果:

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());

    ...
}

【讨论】:

    猜你喜欢
    • 2015-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-16
    • 2014-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多