我有大量未缩放的浮点数-数组长度为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时是否有一种方法可以控制空间/内存位置
基础教程推荐
- 使用 SSH 远程调试 Linux 上的 .NET Core 2023-09-27
- C#基于HttpWebRequest实现发送HTTP请求的方法分析 2023-01-11
- C#开发可播放摄像头及任意格式视频的播放器 2023-01-27
- 快速了解c# 结构体 2023-03-04
- c# – 如何在我的所有Windows上添加通用控件? 2023-09-18
- C#读写共享文件夹的方法 2022-12-11
- C#面向对象设计原则之接口隔离原则 2023-05-25
- C# WinForm实现自动更新程序之客户端的示例代码 2023-07-04
- c# RSA非对称加解密及XML&PEM格式互换方案 2023-03-28
- c# – Windows窗体设计器 – 在类前自动添加命名空间 2023-09-19