使用当前同步上下文的并行ForEach

时间:2017-04-11 20:49:45

标签: c# wpf multithreading

我对C#中的线程有点新,但我继承了一个相当多的代码库。我正在看一些似乎在逻辑上按顺序运行的多线程代码段。这是一个例子:

// Draw the nodes.
var factory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
var drawingTasks = new List<Task>(nodePoints.Count);
Parallel.ForEach(nodePoints, nodePoint =>
{
    Task task = factory.StartNew(() => DrawNode(token, nodePoint, groupList), token, TaskCreationOptions.None, factory.Scheduler);
    if (task != null)
        drawingTasks.Add(task);
});

await factory.ContinueWhenAll(drawingTasks.ToArray(), result =>
{
    _event.Publish(new MapNodesDrawnEvent());
});

调试应用程序显示这是在主线程上执行的,我假设它也是UI线程。由于新线程正在使用当前同步上下文,这不仅仅是在主线程上顺序执行所有这些任务吗?如果是这样,这样做有什么价值吗?

1 个答案:

答案 0 :(得分:3)

  1. List<Task>不是线程安全的,你不能在没有锁定的Parallel.ForEach内使用它(即使你预先确定了列表的大小,它仍然是不安全的。)
  2. 如果你正在做的就是启动一个带有TaskFactory的新线程,那么没有理由并行执行。调用StartNew非常快,所以没有必要。
  3. Parallel类使用调用线程作为工作线程之一,因此调用线程可以在Parallel.ForEach中使用
  4. 您调用TaskScheduler.FromCurrentSynchronizationContext()如果从设置了SynchronizationContext的线程调用,则可能是UI线程或调用了SynchronizationContext.SetSynchronizationContext(的后台线程,将导致使用该调度程序启动的任务从UI线程运行。
  5. 发布的代码给你的唯一的东西(如果你修复了问题1所以它不再是bug)将是你将工作排队到要处理的消息队列的末尾。如果您希望将工作推迟到以后,这可能很有用,但使用Dispatcher.BeginInvoke是一种更好的方法。