【问题标题】:Multiple Parallel Task.ContinueWith order of execution多个并行Task.ContinueWith执行顺序
【发布时间】:2013-10-18 04:55:34
【问题描述】:

问题

这可能是我错过的一些简单的事情。

假设我愿意(在 loveley VB 中):

Dim t1 As New Task(Sub() Debug.WriteLine("t1"))
Dim t2 As Task = t1.ContinueWith(Sub() Debug.WriteLine("t2"))
Dim t3 As Task = t1.ContinueWith(Sub() Debug.WriteLine("t3"))
t1.Start()

注意 t1.ContinueWith 被使用了两次。这些任务的首选执行顺序是什么?对我来说,要么是随机的,要么是错误的。

为什么?

我想这样做的原因...

  1. 创建一个获取和返回数据的任务
  2. 随后是一个“整理”TaskScheduler.FromCurrentSynchronizationContext()(UI 线程)上的 UI 的任务
  3. 按照原始数据抓取任务,将数据转换为长报告(需要很长时间)
  4. 返回 UI 线程,将该报表分配给预览控件
  5. 清理(摆脱我的进度动画等)

由于第 4 步是可选的,这让事情变得更加复杂。

在这一切中,我的任务正在向后弯曲以设置成员属性,以便 UI 和任务可以很好地发挥作用。也许我应该完全放弃任务结果,只坚持同步我的成员变量。毕竟它们都只分配一次。

谢谢,汤姆

【问题讨论】:

  • 等一下,它可能是一个堆栈。如果我执行 t3 然后 t2 它可以工作(无论如何,在我的代码中,我实际上并没有使用 t1 t2 t3 示例)......以错误的顺序添加它们感觉不对。也许我可以有一个延续任务列表,将其反转,然后 .ContinueWith(myreversedTask)

标签: .net task-parallel-library


【解决方案1】:

任务以 LIFO 顺序执行,以获得更好的内存局部性。如果您使用不同的调度程序或者 MS 决定“修复”原始调度程序,这当然可以更改。我不认为你应该依赖这种行为。相反,您可以解开您的任务以在前一个任务完成后继续处理它。否则你在等待错误的事情。更多信息可以在这里找到:http://msdn.microsoft.com/en-us/library/ee795275.aspx

【讨论】:

  • 谢谢你,Alois,这正是我所需要的。我一直在通过 TPL MSDN 上下,而 Unwrapping 从来没有发生在我身上。我现在要读一读。不依赖这种行为是要走的路:)
  • “任务以 LIFO 顺序执行,以获得更好的内存局部性。”这意味着什么?第二个只有在第一个完成后才运行?我没有从你链接到的文章中得到。查看 ContinueWith 的文档,我得到的印象是没有这样的订购保证,并且它们可能会同时运行 - docs.microsoft.com/en-us/dotnet/api/… 另请参阅 blog.stephencleary.com/2015/01/…
【解决方案2】:

如果你想强制执行 t2 和 t3 之间的顺序,为什么不改变 is 让 t3 从 t2 继续而不是 t1?

Dim t1 As New Task(Sub() Debug.WriteLine("t1"))
Dim t2 As Task = t1.ContinueWith(Sub() Debug.WriteLine("t2"))
Dim t3 As Task = t2.ContinueWith(Sub() Debug.WriteLine("t3"))
t1.Start()

如果 t2 和 t3 长时间运行,它们将按照您编写的那样并行执行。

无需创建自定义任务调度程序即可更改此行为。

【讨论】:

  • 啊,原因是 t2 是可选的,我可能根本不希望它运行。我想这是将任务作为一种流控制机制来混淆视听。在我现在的解决方案中,我将许多任务功能组合在一起以解决这种疯狂问题(只是让代码看起来更干净的一种方式)。
【解决方案3】:

根据您对 Ian Mercer 回答的评论,我建议类似

Task t1 = new Task((_)=>Console.WriteLine("t1"));
Task tn = secondTaskCondition ? t1.ContinueWith((_)=>Console.WriteLine("t2")) : t1;
Task t3 = tn.ContinueWith((_)=>Console.WriteLine("t3"));
t1.Start();

这为您提供确定性执行,并且仍然允许您使用可选单元来组合您的工作流程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-05
    • 1970-01-01
    • 1970-01-01
    • 2014-10-20
    • 2017-08-23
    • 1970-01-01
    相关资源
    最近更新 更多