【问题标题】:AsParallel.ForAll vs Parallel.ForEachAsParallel.ForAll 与 Parallel.ForEach
【发布时间】:2012-12-21 19:47:41
【问题描述】:

下面的代码sn-ps有什么区别吗?如果有,是什么?

myList.AsParallel().ForAll(i => { /*DO SOMETHING*/ });

Parallel.ForEach(mylist, i => { /*DO SOMETHING*/ });

主线程会等待所有子线程完成吗?在 MVC 应用程序中,如果我在控制器操作中进行并行处理,那么在主线程完成后子线程会发生什么情况。它们会被中止还是在主线程完成后也会完成?

【问题讨论】:

  • 建议大家阅读:reedcopsey.com/2010/02/03/…
  • 如果我是你,我会为你的 MVC 并行处理问题打开另一个问题。
  • 请小心 AsParallel().ForAll(),因为它会导致不可预测的结果。例如,我有一个按钮可以在单击时执行此代码: myEnumerable.AsParallel().ForAll(i as string => otherDictionary.Add(i, 0)) 。它会将 null 作为 key 添加到 otherDictionary。我不得不重写以使用 foreach 循环。很奇怪。
  • @YukiSakura,也许你没有使用 ConncurrentDictionary?我认为我们不应该因为没有完整示例的注释而害怕使用使用代码。最好将您的问题作为一个单独的问题发布。

标签: c# parallel-processing task-parallel-library


【解决方案1】:

Concurrency in C# Cookbook中所写:

Parallel 和 PLINQ 之间的一个区别是,PLINQ 假定它可以使用计算机上的所有内核,而Parallel 将动态响应 CPU 条件的变化。

【讨论】:

    【解决方案2】:

    这是MSDN中的解释:

    https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/potential-pitfalls-with-plinq#prefer-forall-to-foreach-when-it-is-possible

    根据我阅读的内容,如果您想确保列表被顺序访问,请使用Parallel.ForEach(),而使用AsParallel.ForAll() 并不能保证列表中的项目按顺序访问。

    对于 MVC,所有线程都是基于请求的。调用者线程(main)被阻塞,直到 Parallel() 调用完成,这意味着所有子线程也应该已经完成​​。

    如果调用者线程正在中止,这里有一个解释:

    http://www.albahari.com/threading/part5.aspx

    PLINQ 不会抢先中止线程,因为存在以下危险: 这样做。相反,取消后它会等待每个工作线程 在结束查询之前完成其当前元素。这意味着 查询调用的任何外部方法都将运行完成。

    【讨论】:

      【解决方案3】:

      您可以选择使用 AsParallel().AsOrdered() 对元素进行排序。 Parallel.ForEach 订购不是开箱即用的,我们需要这样做。

      【讨论】:

      • AsOrdered() 会影响 results 的排序。而且由于ForAll() 没有任何结果,AsOrdered() 在这里不会有任何影响。如果您谈论的是处理顺序,那仅对单线程计算有意义。
      • 我是说你使用 ForAll() 和 AsOrdered() 吗?请检查。
      • 对不起,我的错误。但是将 AsOrdered 与 Parallel.ForEach 一起使用更没有意义,原始的非并行集合已经排序,因此添加 .AsParallel().AsOrdered() 不会有任何效果。此外,尝试对并行计算进行排序几乎没有意义。
      【解决方案4】:

      Parallel.ForEach() 就是专门为这种代码设计的。

      另一方面,ForAll() 旨在用于(可能很复杂)PLINQ 查询的末尾。

      因此,我认为Parallel.ForEach() 是这里更好的选择。

      在这两种情况下,当前线程将用于执行计算(以及线程池中的一些线程),并且该方法仅在所有处理完成后才返回。

      【讨论】:

      • 为什么要在 PLINQ 查询的末尾使用 ForAll()?
      • @AranMulholland 根据Reed Copsey,Parallel.Foreach() 使用的并行查询必须支付两次并行化的成本。而 ForAll() 使用查询中的现有分区/线程。
      • 我猜因为Parallel.ForEach() 来自System.Threading.Tasks 命名空间,所以它更可能与任务相关。虽然 AsParallel().ForAll 来自 System.Linq 命名空间,因此更可能与 PLINQ 一起使用。
      • @Ben 我不太明白 ForAll 是 PLINQ 的一部分。而且我不知道“与任务相关”是什么意思。
      猜你喜欢
      • 2011-06-27
      • 2012-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-06
      • 2011-04-16
      • 1970-01-01
      相关资源
      最近更新 更多