我有大量未缩放的浮点数-数组长度为40,000,000.为了扩展此数组,我认为使用Parallel.For()会更有效.这是用于缩放数据的for循环的顺序版本:for (i = 0; i rawData.Length; i++){scaledData[i] = rawData[i] * scal...

我有大量未缩放的浮点数-数组长度为40,000,000.为了扩展此数组,我认为使用Parallel.For()会更有效.这是用于缩放数据的for循环的顺序版本:
for (i = 0; i < rawData.Length; i++)
{
scaledData[i] = rawData[i] * scale + offset;
}
这是转换为使用Parallel.For()的代码,例如:
Parallel.For(0, rawData.Length, i => {
scaledData[i] = rawData[i] * scale + offset;
});
但是性能更差!基于观察索引/线程组合,我的猜测是Parallel.For()正在以导致过多分页的方式访问内存.为了验证这一理论,我尝试使用Parallel.Invoke()像这样:
Parallel.Invoke(
() => { for (int i = 0; i < 10000000; i++) { dst[i] = src[i] * scale + offset; } },
() => { for (int i = 10000000; i < 20000000; i++) { dst[i] = src[i] * scale + offset; } },
() => { for (int i = 20000000; i < 30000000; i++) { dst[i] = src[i] * scale + offset; } },
() => { for (int i = 30000000; i < 40000000; i++) { dst[i] = src[i] * scale + offset; } },
);
这样做的效果明显更好,但是我讨厌这段代码的硬编码性质.我有4个处理器,这就是为什么有4个动作传递给Invoke()的原因.
有没有办法让Parallel.For()以不会破坏内存的方式将索引分配给线程?
解决方法:
您可以使用自定义分区程序来获得所需的行为,而不必诉诸使用Parallel.Invoke. RangPartitioner是您要开始的.
var rangePartitioner = Partitioner.Create(0, rawData.Length);
double[] results = new double[rawData.Length];
Parallel.ForEach(rangePartitioner, (range, loopState) =>
{
for (int i = range.Item1; i < range.Item2; i++)
{
scaledData[i] = rawData[i] * scale * offset;
}
});
您可以创建一个自定义分区程序并使GetPartition() method重载,以将块大小调整为适合您的需求.
有关详细讨论,请参见Custom Partitioners for PLINQ and TPL.
是的,这会改善数据的局部性吗?前提是您的数组包含值类型.在这种情况下,它们将被分配为连续内存块.对于引用类型,情况并非如此. FWIW我试图通过OK来改善这样的内存局部性,但并没有令人惊讶的改进.我得出的结论是,CLR可能还会有许多其他的内存访问,这可能会使您很难理解最终的内存访问模式.
本文标题为:c#-使用Parallel.For时是否有一种方法可以控制空间/内存位置


基础教程推荐
- unity中点击某一个按钮播放某一个动作的操作 2023-04-10
- C#实现简单打字游戏 2023-02-16
- C#利用Spire.Pdf包实现为PDF添加数字签名 2023-07-04
- Winform利用分页控件实现导出PDF文档功能 2023-07-18
- 浅谈c#中config.exe 引发的一些问题 2022-11-26
- C#使用HttpWebRequest重定向方法详解 2023-01-22
- WPF利用ValueConverter实现值转换器 2023-07-18
- Unity实现旋转扭曲图像特效 2023-01-16
- CentOS7下使用Docker容器化.net Core 2.2 2023-09-28
- C#使用正则表达式 2023-05-30