我们很多人可能会开始以非并行的方式实现某些东西,然后需要重构代码并采用并行性。是否有任何关于如何有效地找到并行性热点函数或代码片段的理论或建议。
例如,我可能有非平行样式的以下代码:
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();
}
);
}
行。即使我读了一些内容并且知道为每个向量元素添加随机数的实际任务与创建委托的成本相比较小,并且使用范围来使每个并行任务更加丰富,并行版本仍然比顺序版本慢。在这一点上,我会迷路:所以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倍。
是否有可能出现内存分配/缓存问题?
编辑:显然,在上面的例子中,内存问题不太可能导致并行速度变慢。真的需要找出原因...
答案 0 :(得分:1)
我找到了放慢速度的地方。共享的Random对象会破坏性能。当我找到rand线程时,我会加快速度。并行版本比我的四核机器上的顺序版本大约快4倍。但对于任何富有洞察力的建议,问题仍然是开放的。
答案 1 :(得分:0)
资料。当你发现一些缓慢的事情时,看看它是否正在进行可并行化的操作。这些是你“平行主义的热点”。