【问题标题】:Is PLinq Inherently Faster than System.Threading.Tasks.Parallel.ForEachPLinq 本质上是否比 System.Threading.Tasks.Parallel.ForEach 快
【发布时间】:2011-03-04 16:09:05
【问题描述】:

总结:我从 System.Threading.Tasks.Parallel.ForEach 和 Concurrent Data 结构改为简单的 plinq(Parallel Linq)查询。速度提升是惊人的

那么 plinq 天生就比 Parallel.ForEach 快吗?还是特定于任务。

// Original Code
// concurrent dictionary to store results
var resultDict = new ConcurrentDictionary<string, MyResultType>();

Parallel.ForEach(items, item =>
        {
            resultDict.TryAdd(item.Name, PerformWork(source));
        });


// new code

var results =
            items
            .AsParallel()
            .Select(item => new { item.Name, queryResult = PerformWork(item) })
            .ToDictionary(kv => kv.SourceName, kv => kv.queryResult);

注意事项: 现在,每个任务 (PerformWork) 的运行时间在 0 到 200 毫秒之间。在我优化它之前,它曾经需要更长的时间。这就是我首先使用 Tasks.Parallel 库的原因。所以我从 2 秒的总时间到 ~100-200 毫秒的总时间,执行大致相同的工作,只是使用不同的方法。 (哇 linq 和 plinq 太棒了!)

问题

  1. 使用 plinq 与 Parallel.ForEach 是否会加快速度?
  2. 是不是简单地删除了并发数据结构(ConcurrentDictionary)? (因为它不需要同步线程)。
  3. 基于此related question 的回答

PLINQ 主要基于没有副作用的函数式编程风格,而副作用正是 TPL 的用途。如果您想实际并行工作而不是并行搜索/选择事物,则使用 TPL。

我可以假设因为我的模式基本上是功能性的(给输入产生没有突变的新输出),plinq 是正确使用的技术吗?

我正在寻找我的假设是否正确的验证,或者是我遗漏了什么的迹象。

【问题讨论】:

  • 你的“items”变量是什么数据类型,里面有多少个项目?

标签: c# linq concurrency task-parallel-library plinq


【解决方案1】:

不可能使用这 2 个代码示例在 Parallel.ForEach 和 PLINQ 之间进行明确的比较。代码示例太不同了。

我跳出来的第一个项目是第一个样本使用ConcurrentDictionary,第二个使用Dictionary。这两种类型具有非常不同的用途和性能特征。为了在这两种技术之间进行准确的比较,您需要在此处与类型保持一致。

【讨论】:

  • 如何使用 Parallel.ForEach 加载常规的通用字典?
  • @Chris 我不确定没有某种锁定是否可行。
  • @JarePar 对。这就是我的问题的背景(尽管可能没有很好地说明)。我如何并行执行某些操作并返回字典。在这种情况下,plinq 要快得多。这是可以推广到一类问题还是仅仅是 ConcurrentDictionary 的一个怪癖。
  • @Chris,看起来您的主要目标是并行执行投影操作。如果是这样,那么我认为 PLINQ 在这里更好,不一定是出于性能原因,而是因为它提供了一个直接支持该场景的 API。 Parallel.Foreach 不提供与 AFAIK 相同的投影功能。
  • 实际上,PLINQ 示例使用 ToDictionary 的事实理论上应该会使其变慢,因为与 ConcurrentDictionary 不同,项目不能并行添加。实际上,如果您查看 ParallelEnumerable 的 ToDictionary 实现,它实际上会从上游并行查询中提取项目,因为它们以串行方式可用,以一次将它们添加到 Dictionary 中。所以,至少在这方面,他的 Parallel::ForEach 应该表现更好。请参阅我的答案,了解为什么我认为不是。
【解决方案2】:

根据您在示例中提供的有限信息(我在对 OP 的评论中询问了更多详细信息),我猜您肯定会看到由于使用的分区算法而导致的差异。您应该阅读这篇博文中的Chunk Partitioning vs. Range Partitioning,他在其中讨论了它们的不同之处以及它们最适合的工作类型。强烈建议您阅读该博客文章以及this one,其中更详细地介绍了这两种类型以及可以使用的其他两种类型的分区,但不适用于您的示例,以及提供一些视觉帮助以便更好地理解分区。最后,here's yet another blog post 讨论了工作分区以及当默认分区算法对您的特定工作负载没有意义时它如何影响您。那篇文章实际上提到了一个很棒的程序,它可以帮助您可视化工作中的分区器,它是a set of parallel samples from the PFX team 的一部分。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-01
    • 1970-01-01
    相关资源
    最近更新 更多