我有一个C程序可以并行化.我使用Visual Studio 2010,32位编译.
简而言之,程序的结构如下
#define num_iterations 64 //some number struct result { //some stuff } result best_result=initial_bad_result; for(i=0; i<many_times; i++) { result *results[num_iterations]; for(j=0; j<num_iterations; j++) { some_computations(results+j); } // update best_result; }
由于每个some_computations()是独立的(一些全局变量被读取,但没有全局变量被修改)我并行内部for循环.
我的第一个尝试是使用boost :: thread,
thread_group group; for(j=0; j<num_iterations; j++) { group.create_thread(boost::bind(&some_computation,this,result+j)); } group.join_all();
结果是好的,但我决定尝试更多.
我试过OpenMP库
#pragma omp parallel for for(j=0; j<num_iterations; j++) { some_computations(results+j); }
结果比boost :: thread的更差.
然后我尝试了ppl库并使用parallel_for():
Concurrency::parallel_for(0,num_iterations,[=](int j) { some_computations(results+j); })
结果是最糟糕的.
我发现这个行为挺令人惊讶的.由于OpenMP和ppl是为了并行化而设计的,所以我会期望比boost :: thread更好的结果.我错了吗?
为什么boost :: thread给我更好的结果?
解决方法
OpenMP或PPL不要这么悲观.他们只是按照他们被告知的做法,但是当你试图让paralellize循环有一些事情你应该考虑到.
没有看到你如何实现这些事情,很难说出真正的原因是什么.
另外,如果每个迭代中的操作对同一循环中的任何其他迭代有一些依赖关系,那么这将产生争用,这将减慢事情的发生.你没有显示你的some_operation功能实际上是什么,所以很难判断是否有数据依赖.
可以真正并行化的循环必须能够使每个迭代完全独立于所有其他迭代,在任何迭代中都不会访问共享内存.所以最好你会写东西到局部变量,然后在最后复制.
并不是所有的循环都可以并行化,它非常依赖于正在完成的工作类型.
例如,适用于并行化的功能正在屏幕缓冲区的每个像素上进行.每个像素完全独立于所有其他像素,因此,线程可以进行一个循环的迭代,并且不需要等待循环内的共享存储器或数据依赖关系就可以进行工作.
另外,如果你有一个连续的数组,这个数组可能部分地在缓存行中,如果你正在编辑线程A中的元素5,然后在线程B中修改元素6,你可能会获得缓存争用,这也会减慢事情,因为它们将驻留在同一个高速缓存行中.一种被称为虚假共享的现象.
进行循环并行处理时,需要考虑很多方面.