我正在尝试使用openMP使我的quicksort工作并行。在实施openMP之后,我试图使quicksort工作更快失败,我的quicksort对数组的排序几乎慢两倍。我的代码使用openMP实现:
void quickSort( int a[], int l, int r) {
int j;
if( l < r ) {
#pragma omp parallel
{
j = partition( a, l, r);
#pragma omp sections
{
#pragma omp section
{
quickSort( a, l, j-1);
}
#pragma omp section
{
quickSort( a, j+1, r);
}
}
}
}
}
整个排序发生在方法分区中,如果它对你有用,它的工作原理就是代码:
int partition( int a[], int l, int r) {
int pivot, i, j, t;
pivot = a[l];
i = l; j = r+1;
while(1) {
do ++i; while( a[i] <= pivot && i <= r );
do --j; while( a[j] > pivot );
if( i >= j ) break;
t = a[i]; a[i] = a[j]; a[j] = t;
}
t = a[l]; a[l] = a[j]; a[j] = t;
return j;
}
在我调用quickSort之前,我需要花时间在主要部分,然后在printf之前停止计时器。 线程数被定义为10(我在我的电脑上尝试过4,2和1)。我在使用0 - 100之间的1 000 000个随机整数排序列表后的结果:
时间(没有openMP)在6.48004 - 5.32001
之间openMP时间是11.8309和10.6239(2-4线程) 这怎么可能是真的?
答案 0 :(得分:3)
quicksort的一般想法是:
[......................]
该元素列表分为两个任务:
[..........][..........]
然后一次又一次地拆分每个“任务”:
[..][..][..][..][..][..]
现在,CPU喜欢处理紧密相关的数据。但是,当每个核心处理数据PRETTY closeley时,可能会出现这样的情况,即一个核心写入与同一个高速缓存行上的数据块与不同核心上的数据。由于您不希望核心写入彼此的数据,因此第一次写入将使其他核心中的数据无效,因此其他核心必须再次获取ram块。
|--- cache line ---|
[..][..][..][..][..][..]
^ ^ ^ ^
| | | |
c1 c2 c3 c4
因此,无论哪个核心写入属于该缓存行的数据,都会使所有其他核心的数据无效。由于您使小任务[..]
非常接近,因此增加了大量无效高速缓存行的可能性以及大量从内存中重新获取数据的可能性。这里的效果更好解释
http://fgiesen.wordpress.com/2013/01/31/cores-dont-like-to-share
另请阅读http://lwn.net/Articles/252125/,尤其是“3.3.4多处理器支持”。
由于只有一个核心正在积极处理数据,因此整个invalidating the cache
在非并行版本中不会发生(通常)。
所以,一个可能的解决方案是不要将任务分开,直到它们太小而无法被核心有效地处理。您必须考虑的另一个影响:OpenMP必须为每个任务执行一些management overhead
。如果任务太小,您还会增加overhead vs work
比率。
谷歌吐出的基于OpenMP的快速搜索是:
http://berenger.eu/blog/c-openmp-a-shared-memory-quick-sort-with-openmp-tasks-example-source-code/
祝你振奋。