如何在openmp中并行化do-while和while循环

How to parallelize do while and while loop in openmp?

本文关键字:do-while while 循环 并行化 openmp      更新时间:2023-10-16

我正在尝试使用OpenMP学习并行编程,并且我对以下包含多个while循环的do while循环的并行化感兴趣:

do {
        while(left < (length - 1) && data[left] <= pivot) left++;
        while(right > 0 && data[right] >= pivot) right--;
        /* swap elements */
        if(left < right){
            temp = data[left];
            data[left] = data[right];
            data[right] = temp;
        }
    } while(left < right);

实际上,我还没有弄清楚如何并行化whiledo while循环,找不到任何具体描述如何并行化whiledo while循环的资源。我已经找到了for循环的指令,但我不能据此对whiledo while循环做出任何假设。那么,你能描述一下我如何并行化我在这里提供的循环吗?

编辑

我已经将do while循环转换为以下代码,其中仅使用for循环。

for(i = 1; i<length-1; i++)
{
    if(data[left] > pivot)
    {
        i = length;
    }
    else
    {
        left = i;
    }
}
for(j=length-1; j > 0; j--)
{
    if(data[right] < pivot)
    {
        j = 0;
    }
    else
    {
        right = j;
    }
}
/* swap elements */
if(left < right)
{
    temp = data[left];
    data[left] = data[right];
    data[right] = temp;
}
int leftCopy = left;
int rightCopy = right;
for(int leftCopy = left; leftCopy<right;leftCopy++)
{
    for(int new_i = left; new_i<length-1; new_i++)
    {
        if(data[left] > pivot)
        {
            new_i = length;
        }
        else
        {
            left = new_i;
        }
    }
    for(int new_j=right; new_j > 0; new_j--)
    {
        if(data[right] < pivot)
        {
            new_j = 0;
        }
        else
        {
            right = new_j;
        }
    }
    leftCopy = left;
    /* swap elements */
    if(left < right)
    {
        temp = data[left];
        data[left] = data[right];
        data[right] = temp;
    }
}

这段代码运行良好,产生了正确的结果,但当我试图将上述代码的部分并行化时,通过将前两个for循环更改为以下循环:

#pragma omp parallel default(none) firstprivate(left) private(i,tid) shared(length, pivot, data)
    {
#pragma omp for
        for(i = 1; i<length-1; i++)
        {
            if(data[left] > pivot)
            {
                i = length;
            }
            else
            {
                left = i;
            }
        }
    }

#pragma omp parallel default(none) firstprivate(right) private(j) shared(length, pivot, data)
    {
#pragma omp for
        for(j=length-1; j > 0; j--)
        {
            if(data[right] < pivot)
            {
                j = 0;
            }
            else
            {
                right = j;
            }
        }
    }

速度比非并行代码差。请帮我找出我的问题。

感谢

首先,排序算法很难与OpenMP并行循环并行。这是因为循环跳闸计数不是确定性的,而是取决于每次迭代读取的输入设置值。

我认为data[left] <= pivot这样的循环条件不会很好地工作,因为OpenMP库不知道如何在线程之间划分迭代空间。

如果你仍然对并行排序算法感兴趣,我建议你先阅读文献,看看那些由于其可扩展性而真正值得实现的算法。如果你只是想学习OpenMP,我建议你从更简单的算法开始,比如bucket排序,其中bucket的数量是众所周知的,并且不会经常改变。

关于您尝试并行化的示例,OpenMP不直接支持while循环,因为迭代次数(循环行程计数)是不确定的(否则,很容易将它们转换为for循环)。因此,不可能在线程之间分配迭代。此外,while循环通常使用上一次迭代的结果来检查条件。这被称为Read after Writetrue dependency,无法并行化。

如果你尽量减少omp parallel子句的数量,你的减速问题可能会得到缓解。此外,尝试将它们从所有循环中移出。这些子句可能会创建和连接代码并行部分中使用的额外线程,这是非常昂贵的。

您仍然可以在并行块中同步线程,这样结果是相似的。事实上,默认情况下,所有线程都会在omp for子句的末尾相互等待,因此这会使事情变得更加容易。

#pragma omp parallel default(none) firstprivate(right,left) private(i,j) shared(length, pivot, data)
{
    #pragma omp for
    for(i = 1; i<length-1; i++)
    {
        if(data[left] > pivot)
        {
            i = length;
        }
        else
        {
            left = i;
        }
    }
    #pragma omp for 
    for(j=length-1; j > 0; j--)
    {
        if(data[right] < pivot)
        {
            j = 0;
        }
        else
        {
            right = j;
        }
    }
} // end omp parallel