【问题标题】:Partitioning in TPL using Partitioner使用 Partitioner 在 TPL 中进行分区
【发布时间】:2014-06-18 19:28:39
【问题描述】:

我发现以下两个功能相似的代码之间存在微小的性能差异,我希望有人能够帮助我理解为什么会有差异。

//Case 1 Faster
Parallel.ForEach(data, x => func(x)) 

//Case 2 Slower
Parallel.ForEach(Partitioner.Create(data), x => func(x)) 

数据的类型是 List

据我了解,第一种情况下的默认分区也会和Partitioner.Create(data)类似,所以性能上应该没有区别。

有没有办法弄清楚分区是如何在运行时完成的?

【问题讨论】:

  • 根据 msdn 文档,通过创建分区程序,您可以对每个线程进行负载平衡。这会产生开销,因为分区器必须将每件工作编组到每个线程,因为它们完成了每个先前的任务。如果您的任务在恒定时间内完成,那么您一开始就不太可能出现不均匀的负载平衡。在这种情况下,静态分区会更合适。 msdn.microsoft.com/en-us/library/dd997411(v=vs.110).aspx
  • 谢谢阿伦。在等待答案时,我编写了一些测试代码(一个新的包装类继承自 IList 并将 Console.WriteLine 添加到每个方法),我发现在第一种情况下它使用 List 索引器,而在第二种情况下它使用枚举器。
  • 您为什么认为两个备选方案相似应该意味着性能没有差异

标签: c# .net .net-4.0 task-parallel-library parallel-extensions


【解决方案1】:

我正在回答我自己的问题,以防有人想知道同样的事情。

我编写了一个继承自 IList 的新 MyList 类,并将所有方法实现为列表实例的包装器以及一个额外的 Console.WriteLine 以进行调试。

有趣的是,在第一种情况下,即使我将 IEnumerable 实例传递给它,它似乎也会找出它是否是下面的列表并调用 List 的索引器函数。而在第二种情况下,它正在调用 GetEnumerator,我认为由于枚举所需的函数调用和同步,它会更慢。如果我传递 data.Select(x=>x) 而不是 data,在第一种情况下也会发生同样的事情。

我猜parallel的实现试图找出IEnumerable是否是一个List,如果可以的话就使用它。

【讨论】:

    猜你喜欢
    • 2016-05-03
    • 1970-01-01
    • 2013-08-31
    • 1970-01-01
    • 2019-07-19
    • 1970-01-01
    • 2016-10-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多