我对 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 线程。由于新线程正在使用当前同步上下文,这不就是在主线程上按顺序执行所有这些任务吗?如果是这样,这样做有什么值(value)吗?
最佳答案
-
List<Task>
不是线程安全的,你不能在Parallel.ForEach
中使用它没有锁定(即使您预先确定了列表的大小,它仍然不安全)。 - 如果您所做的只是使用 TaskFactory 启动一个新线程,则没有理由并行执行此操作。调用 StartNew 的速度非常快,因此没有必要。
Parallel
类使用调用线程作为工作线程之一,因此可以在 Parallel.ForEach 中使用调用线程- 你调用
TaskScheduler.FromCurrentSynchronizationContext()
如果从设置了 SynchronizationContext 的线程调用,这可能是 UI 线程或后台线程SynchronizationContext.SetSynchronizationContext(
调用,将导致使用该调度程序启动的任务从 UI 线程运行。
发布的代码唯一能给您的(如果您解决了问题 1,那么它就不再有错误)是您将工作排到消息队列的末尾进行处理。如果您想将工作推迟到以后使用 Dispatcher.BeginInvoke
,这可能很有用。是一种更好的方法。
关于c# - 使用当前同步上下文的并行 ForEach,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43355959/