有没有人能推荐一些典型的场景,在这些场景中,可以/应该使用.NET 4.0中引入的Partitioner类?
发布于 2010-10-27 17:54:42
Partitioner类用于使并行执行变得更加笨重。如果您有许多非常小的任务要并行运行,则为每个任务调用委托的开销可能会很高。通过使用Partitioner,您可以将工作负载重新安排为块,并让每个并行调用在稍大一点的集合上工作。该类抽象了此功能,并能够根据数据集和可用核心的实际条件进行分区。
例如:假设你想要并行运行一个简单的计算。
Parallel.ForEach(Input, (value, loopState, index) => { Result[index] = value*Math.PI; });这将为输入中的每个条目调用委托。这样做会给每一个都增加一点开销。通过使用Partitioner,我们可以这样做
Parallel.ForEach(Partitioner.Create(0, Input.Length), range => {
for (var index = range.Item1; index < range.Item2; index++) {
Result[index] = Input[index]*Math.PI;
}
});这将减少调用的数量,因为每个调用都将在更大的集合上工作。根据我的经验,在并行化非常简单的操作时,这可以显着提高性能。
发布于 2017-03-04 16:00:01
Range partition,正如Brian Rasmussen所建议的,是一种类型的分区,当工作是CPU密集型的,往往是小的(相对于虚拟方法调用),必须处理许多元素,并且当涉及到每个元素的运行时间时,大多数情况下是恒定的。
应该考虑的另一种分区类型是块分区。这种类型的分区也称为负载平衡算法,因为当有更多工作要做时,工作线程很少处于空闲状态-范围分区不是这种情况。
当工作有一些等待状态,倾向于每个元素需要更多的处理,或者每个元素有明显不同的工作处理时间时,应该使用块分区。
这方面的一个例子可能是读入内存并处理100个大小差别很大的文件。与1mb文件相比,处理1K文件所需的时间要短得多。如果使用范围分区,那么一些线程可能会空闲一段时间,因为它们恰好处理较小的文件。
与范围分区不同,无法指定每个任务要处理的元素数量-除非您编写自己的自定义分区程序。使用区块分区的另一个缺点是,当它返回获取另一个区块时,可能会有一些争用,因为在这一点上使用了排它锁。因此,显然块分区不应该用于少量的CPU密集型工作。
默认的块分区程序以每个块1个元素的块大小开始。在每个线程处理三个包含1个元素的块之后,块大小将增加到每个块2个元素。在每个线程处理了三个包含2个元素的块之后,块大小再次增加到每个块3个元素,依此类推。至少根据为微软工作的Dixin Yan的说法,这是它的工作方式(参见块分区部分)。
顺便说一句,在他的博客中很好的可视化工具似乎是Concurrency Visualizer profile tool。docs for this tool声称它可用于定位性能瓶颈、CPU未充分利用、线程争用、跨核心线程迁移、同步延迟、DirectX活动、重叠I/O区域以及其他信息。它提供图形、表格和文本数据视图,显示应用程序中的线程和整个系统之间的关系。
其他资源:
MSDN: Custom Partitioners for PLINQ and TPL
约瑟夫·阿尔巴哈里的Part 5: Parallel Programming - Optimizing PLINQ
发布于 2010-10-27 17:50:17
要并行化数据源上的操作,其中一个基本步骤是将数据源划分为多个可由多个线程并发访问的部分。PLINQ和任务并行库提供了默认的分割器,它们在编写并行查询或ForEach循环时透明地工作。对于更高级的场景,您可以插入自己的分区程序。
阅读更多here
https://stackoverflow.com/questions/4031820
复制相似问题