5

在哪些场景下Range分区会比Chunk分区更好?(和虎钳诗句)

我已经知道了

  • 块分区:从输入中抓取小块元素进行处理,然后从小块开始,然后增加块大小。

  • 范围分区为每个工作人员预分配相等数量的元素

另外,为什么这个代码:(找到直到 100000 的素数)

IEnumerable<int> numbers = Enumerable.Range (3, 100000-3);
var parallelQuery =    from n in numbers.AsParallel()
                       where Enumerable.Range (2, (int) Math.Sqrt (n)).All (i => n % i > 0)
                       select n;

范围分区可能表现不佳

虽然这段代码:(找到前一百万个数字的 sqrt 总和)

ParallelEnumerable.Range (1, 10000000).Sum (i => Math.Sqrt (i))

与范围分区一起使用会是更好的选择吗?

4

2 回答 2

5

在第一个示例中,每个项目所需的时间取决于n. 寻找 90000 之后的下一个素数比寻找 11 之后的素数花费更多的时间。

结果,当划分为相等的范围时,最后一个范围将比第一个范围执行更多的工作。

在第二个样本中,每次操作的时间在整个范围内都是相等的。所以范围分区会很好地工作。

于 2012-09-01T15:41:10.283 回答
1

微软 PFX 团队的成员在 PFX 开发博客上给出了很好的解释:

PLINQ 中的分区

基于许多因素,我们有 4 种主要算法单独用于分区。它们值得了解,因为我们将在未来的技术讨论中更多地讨论它们以及我们对它们所做的调整。

  1. 范围分区——这是一种非常常见的分区方案,类似于我在上面的示例中描述的那个。这适用于许多查询形状,尽管它仅适用于可索引的数据源,例如列表和数组(即 IList 和 T[])。如果您为 PLINQ 提供类型为 IEnumerable 或 IEnumerable 的内容,PLINQ 将查询 ILIst 接口,如果找到,将使用该接口实现和范围分区。这些数据源的好处是我们知道确切的长度并且可以直接访问数组中的任何元素。在大多数情况下,使用这种类型的分区有很大的性能优势。

范围分区

  1. 块分区 - 这是适用于任何数据源的通用分区方案,并且是不可索引数据源的主要分区类型。在这个方案中,工作线程请求数据,并以块的形式提供给线程。IEnumerables 和 IEnumerables 没有固定的 Count 属性(有一个 LINQ 扩展方法,但不一样),因此无法知道数据源何时或是否会完全枚举。可以是 3 个元素,可以是 300 万个元素,也可以是无限的。单个系统需要考虑所有这些可能性,并考虑不同的委托大小、不均匀的委托大小、选择性等。块分区算法非常通用,必须调整 PLINQ 的算法才能在各种查询上获得良好的性能。我们已经尝试了许多不同的增长模式,目前使用的计划是在一定数量的请求后翻倍。当我们调整性能时,这可能会发生变化,所以不要依赖于此。另一个重要的优化是块分区平衡了核心之间的负载,因为每个核心的任务会根据需要动态地请求更多的工作。这确保了在整个查询过程中使用了所有核心,并且都可以同时越过终点线,而不是一个参差不齐的顺序进入到最后。

块分区

  1. 条带分区——该方案用于 SkipWhile 和 TakeWhile,并针对处理数据源头部的项目进行了优化(这显然适合 SkipWhile 和 TakeWhile 的需求)。在条带分区中,n 个工作线程中的每一个都从 n 个项目的每个块中分配了少量项目(有时是 1)。属于单个线程的一组项目称为“条带”,因此得名。该方案的一个有用特性是不需要线程间同步,因为每个工作线程都可以通过简单的算术确定其数据。这实际上是范围分区的一种特殊情况,仅适用于实现 IList 的数组和类型。

条带分区

  1. 哈希分区 – 哈希分区是一种特殊类型的分区,供必须比较数据元素的查询运算符使用(这些运算符是:Join、GroupJoin、GroupBy、Distinct、Except、Union、Intersect)。当散列分区发生时(就在提到的任何运算符之前),所有数据都被处理并引导到线程,这样具有相同散列码的项目将由同一个线程处理。这种哈希分区工作的成本很高,但这意味着所有的比较工作都可以在没有进一步同步的情况下执行。散列分区基于从每个元素的键计算的散列将每个元素分配给输出分区。这可以是一种有效的同时构建哈希表的方法,并且可以用于为哈希连接算法完成分区和哈希。好处是 PLINQ 现在可以对用于探测的数据源使用相同的哈希分区方案;这样所有可能的匹配最终都在同一个分区中,这意味着更少的共享数据和更小的哈希表大小(每个分区都有自己的哈希表)。哈希分区有很多事情要做,所以它不像其他类型那么快,尤其是在查询中涉及排序时。因此,与更简单的运算符相比,依赖它的查询运算符具有额外的开销。所以它不像其他类型那么快,尤其是在查询中涉及排序时。因此,与更简单的运算符相比,依赖它的查询运算符具有额外的开销。所以它不像其他类型那么快,尤其是在查询中涉及排序时。因此,与更简单的运算符相比,依赖它的查询运算符具有额外的开销。

哈希分区

于 2021-10-20T18:56:26.213 回答