我们中的许多人可能会从以非并行方式实现某些东西开始,然后需要重构代码并采用并行性。有没有关于如何有效地找到热点函数或并行代码的任何理论或建议。
例如,我可能有以下非并行样式的代码:
int[] data = new int[1000000]; // Just a big trunk of data.
// Here is just a procedure on the trunk of data, performing repeated work.
void SequentialProcedure(){
for(int i = 0; i < data.Length; i++) data[i] += rand.Next();
}
对于像我这样没有太多并行经验的人来说,乍一看,它看起来像是一个可以应用一些花哨的并行技能的函数:
int[] data = new int[1000000]; // The same big trunk of data.
// A parallel implementation.
void ParallelProcedure(){
Parallel.ForEach(Partitioner.Create(0, data.Length),
range => {
for(int i = range.Item1; i < range.Item2; i++) data[i] += rand.Next();
}
);
}
好的。即使我读了一些东西并且知道向每个向量元素添加随机数的实际任务与创建委托(delegate)和使用范围使每个并行任务更丰富的成本相比很小,但并行版本仍然比顺序版本慢.说到这里,我会迷茫:所以 SequentialProcedure 只是一个不适合并行的函数?或者我尝试并行化它的方式是错误的?是否有任何来自专家的建议和指导方针,我们可以遵循以发现并行性会在哪里发挥更大的作用以及并行性只会浪费时间?
非常感谢您的帮助。
编辑:
为了使每次迭代更丰富,我添加了第二级迭代。所以顺序代码变为:
int[] data = new int[100];
void SequentialProcedure(){
for(int i = 0; i < data.Length; i++){
for(int j = 0; j < 500000; j++) data[i] = rand.Next(j, Int32.MaxValue);
}
}
并行版本变为:
int[] data = new int[100];
void ParallelProcedure(){
Parallel.ForEach(Partitioner.Create(0, data.Length),
range => {
for(int i = range.Item1; i < range.Item2; i++){
for(int j = 0; j < 500000; j++) data[i] = rand.Next(j, Int32.MaxValue);
}
}
}
有趣的是,即使现在每个外部迭代都有足够的工作要做,并行过程仍然比我机器上的顺序过程慢近 4 倍。
是否可能存在一些内存分配/缓存问题?
编辑:显然,在上面的示例中,导致并行速度变慢的内存问题不太可能。真的需要弄清楚原因...
最佳答案
我找到了减速的地方。破坏性能的是共享的 Random 对象。当我定位 rand 线程时,我会加快速度。在我的四核机器上,并行版本大约比顺序版本快 4 倍。但是,对于任何有见地的建议,这个问题仍然是开放的。
关于.net - 如何在 .net 4 中找到并行性的热点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4200991/