C++ OpenMP中的并行合并排序
我在一篇论文中看到了并行合并排序算法。代码如下:C++ OpenMP中的并行合并排序,c++,c,multithreading,parallel-processing,openmp,C++,C,Multithreading,Parallel Processing,Openmp,我在一篇论文中看到了并行合并排序算法。代码如下: void mergesort_parallel_omp (int a[], int size, int temp[], int threads) { if ( threads == 1) { mergesort_serial(a, size, temp); } else if (threads > 1) { #pragma omp parallel sections
void mergesort_parallel_omp (int a[], int size, int temp[], int threads)
{
if ( threads == 1) { mergesort_serial(a, size, temp); }
else if (threads > 1)
{
#pragma omp parallel sections
{
#pragma omp section
mergesort_parallel_omp(a, size/2, temp, threads/2);
#pragma omp section
mergesort_parallel_omp(a + size/2, size - size/2, temp + size/2, threads - threads/2);
}
merge(a, size, temp);
} // threads > 1
}
我在多核上运行它。在树的叶子上,两个线程并行运行。在他们完成工作后,另外两个线程开始,依此类推。即使所有叶节点都有空闲的核心
我认为原因是这个OpenMP代码没有在并行区域内创建并行区域。我说得对吗
我认为原因是OpenMP无法创建并行区域
平行区域内
你可以有一个平行区域的平行区域
OpenMP并行区域可以嵌套在彼此内部。如果嵌套
并行性被禁用,然后由线程创建新团队
在并行区域内遇到并行构造包括
仅对遇到的线程执行。如果启用了嵌套并行,
那么新团队可能由多个线程组成
为了正确运行代码,需要调用omp\u set\u nested(1)
和omp\u set\u num\u threads(2)
通过设置
OMP_嵌套环境变量或调用OMP_set_NESTED()函数
为了获得更好的性能,您可以使用OpenMP任务(可以找到有关的详细信息和示例),如下所示:
void merge(int * X, int n, int * tmp) {
...
}
void mergeSort(int *X, int n, int *tmp)
{
if (n < 2) return;
#pragma omp task shared(X) if (n > TASK_SIZE)
mergeSort(X, n/2, tmp);
#pragma omp task shared(X) if (n > TASK_SIZE)
mergeSort(X+(n/2), n-(n/2), tmp + n/2);
#pragma omp taskwait
mergeSortAux(X, n, tmp);
}
int main()
{
...
#pragma omp parallel
{
#pragma omp single
mergesort(data, n, tmp);
}
}
未来的改进将在上提供
一个C++版本的并行版本。最终的算法如下所示:
void mergeSortRecursive(vector<double>& v, unsigned long left, unsigned long right) {
if (left < right) {
if (right-left >= 32) {
unsigned long mid = (left+right)/2;
#pragma omp taskgroup
{
#pragma omp task shared(v) untied if(right-left >= (1<<14))
mergeSortRecursive(v, left, mid);
#pragma omp task shared(v) untied if(right-left >= (1<<14))
mergeSortRecursive(v, mid+1, right);
#pragma omp taskyield
}
inplace_merge(v.begin()+left, v.begin()+mid+1, v.begin()+right+1);
}else{
sort(v.begin()+left, v.begin()+right+1);
}
}
}
}
void mergeSort(vector<double>& v) {
#pragma omp parallel
#pragma omp single
mergeSortRecursive(v, 0, v.size()-1);
}
void mergeSortRecursive(向量&v、无符号长左、无符号长右){
if(左<右){
如果(右-左>=32){
无符号长中=(左+右)/2;
#布拉格马omp任务组
{
#pragma omp task shared(v)untied if(right-left>=(1这个问题的现代答案是使用任务而不是节。任务是在OpenMP 3.0(2009)中添加的,比嵌套并行和节工作得更好/更容易,因为嵌套并行可能导致超额订阅(活动线程比可用CPU更多),这会导致性能显著降低。对于任务,您有一组与CPU数量匹配的线程,并且将处理这些任务。因此,您不需要手动处理threads
参数。简单的解决方案如下所示:
// span parallel region outside once outside
void mergesort_omp(...) {
#pragma omp parallel
#pragma omp single
mergesort_parallel_omp(...)
}
void mergesort_parallel_omp (int a[], int size, int temp[])
{
#pragma omp task
mergesort_parallel_omp(a, size/2, temp);
mergesort_parallel_omp(a + size/2, size - size/2, temp + size/2);
#pragma omp taskwait
merge(a, size, temp);
}
但是,为太小的工作块创建任务仍然会有问题,因此根据工作粒度限制并行性非常有用,例如:
void mergesort_parallel_omp (int a[], int size, int temp[])
{
if (size < size_threshold) {
mergesort_serial(a, size, temp);
return;
}
#pragma omp task
mergesort_parallel_omp(a, size/2, temp);
mergesort_parallel_omp(a + size/2, size - size/2, temp + size/2);
#pragma omp taskwait
merge(a, size, temp);
}
void mergesort\u parallel\u omp(int a[],int size,int temp[])
{
如果(大小<大小\阈值){
mergesort_系列(a、尺寸、温度);
返回;
}
#pragma-omp任务
合并排序\u并行\u omp(a,尺寸/2,温度);
合并排序\u并行\u omp(a+size/2,size-size/2,temp+size/2);
#pragma omp taskwait
合并(a、大小、温度);
}
// span parallel region outside once outside
void mergesort_omp(...) {
#pragma omp parallel
#pragma omp single
mergesort_parallel_omp(...)
}
void mergesort_parallel_omp (int a[], int size, int temp[])
{
#pragma omp task
mergesort_parallel_omp(a, size/2, temp);
mergesort_parallel_omp(a + size/2, size - size/2, temp + size/2);
#pragma omp taskwait
merge(a, size, temp);
}
void mergesort_parallel_omp (int a[], int size, int temp[])
{
if (size < size_threshold) {
mergesort_serial(a, size, temp);
return;
}
#pragma omp task
mergesort_parallel_omp(a, size/2, temp);
mergesort_parallel_omp(a + size/2, size - size/2, temp + size/2);
#pragma omp taskwait
merge(a, size, temp);
}