7

#pragma omp for schedule(static)关于未指定块大小的位置, 我有几个问题。

在 OpenMP 中并行化循环的一种方法是手动执行,如下所示:

#pragma omp parallel 
{
    const int nthreads = omp_get_num_threads();
    const int ithread = omp_get_thread_num();
    const int start = ithread*N/nthreads;
    const int finish = (ithread+1)*N/nthreads;
    for(int i = start; i<finish; i++) {
        //          
    }
}

是否有充分的理由不在 OpenMP 中手动并行化这样的循环? 如果我将这些值与我进行比较,#pragma omp for schedule(static)我发现给定线程的块大小并不总是一致,因此 OpenMP(在 GCC 中)实现的卡盘大小与 和 中定义的start不同finish。为什么是这样?

我定义的startandfinish值有几个方便的属性。

  1. 每个线程最多获得一个块。
  2. 迭代值的范围直接随线程数增加(即对于具有两个线程的 100 个线程,第一个线程将处理迭代 1-50 和第二个线程 51-100,而不是相反)。
  3. 对于完全相同范围内的两个 for 循环,每个线程将运行完全相同的迭代。

编辑:原来我说的是一个块,但经过考虑,如果线程数远大于Nithread*N/nthreads = (ithread*1)*N/nthreads),则块的大小可能为零。我真正想要的财产最多是一大块。

使用时是否保证所有这些属性#pragma omp for schedule(static)

根据 OpenMP 规范:

依赖于哪个线程在任何其他情况下执行特定迭代的程序是不合格的。

具有相同调度和迭代计数的不同循环区域,即使它们发生在同一个并行区域中,也可以在线程之间以不同的方式分配迭代。唯一的例外是静态计划

对于schedule(static)规范说:

块按照线程编号的顺序以循环方式分配给团队中的线程。

此外,该规范对`schedule(static) 进行了说明:

当没有指定chunk_size时,迭代空间被分成大小近似相等的chunk,每个线程最多分配一个chunk。

最后,规范说schedule(static)

如果满足以下条件,静态调度的兼容实现必须确保在两个循环区域中使用相同的逻辑迭代次数分配给线程:1)两个循环区域具有相同的循环迭代次数,2)两个循环区域具有相同的 chunk_size 值,或者两个循环区域都没有指定 chunk_size,3) 两个循环区域绑定到同一个并行区域。

因此,如果我正确阅读此内容,schedule(static)将具有与我列出的相同的方便属性startfinish 即使我的代码依赖于线程执行特定的迭代。 我是否正确解释了这一点? 这似乎schedule(static)是未指定块大小时的特殊情况。

定义更容易startfinish就像我所做的那样,然后尝试中断这种情况的规范。

4

1 回答 1

9

是否有充分的理由不在 OpenMP 中手动并行化这样的循环?

我首先想到的事情是:

  1. 您向 OpenMP 库添加了一个依赖项,因此如果您想维护串行编译,则必须复制部分代码,或者必须为库函数调用提供存根。
  2. 与显式并行化循环相比,工作共享结构需要更少的代码并且更便于阅读。如果您需要维护大型代码库,那将很重要。
  3. 你错过了所有的调度机会schedule(static)
  4. 处理低级细节很容易适得其反。

使用#pragam omp for schedule(static) 时是否保证所有这些属性?

让我们一一来看:

1.) 每个线程都得到一个块

当没有指定chunk_size时,迭代空间被分成大小近似相等的chunk,每个线程最多分配一个chunk。请注意,在这种情况下,未指定块的大小。

最多一块完全是一块。所以属性一没有实现。除此之外,这就是未指定块大小的原因。

2.) 迭代值的范围直接随线程数增加(即对于两个线程的 100 次迭代,第一个线程将处理迭代 1-50 和第二个线程 51-100,而不是相反)

如果满足以下条件,则静态调度的兼容实现必须确保在两个循环区域中使用相同的逻辑迭代编号分配给线程:

  1. 两个循环区域的循环迭代次数相同
  2. 两个循环区域都指定了相同的 chunk_size 值,或者两个循环区域都没有指定 chunk_size
  3. 两个循环区域都绑定到同一个并行区域。

保证满足两个此类循环中相同逻辑迭代之间的数据依赖性,从而允许安全使用 nowait 子句(示例参见第 182 页的第 A.10 节)。

尽管我从未见过与您所说的不同的东西,但我敢说,即使是属性二也没有满足,至少没有满足schedule(static)。在我看来,在某个基数的迭代空间中,唯一的保证是如果条件 1、2 和 3 得到遵守,相同的“逻辑迭代数”将被赋予相同的线程。

如果您指定块大小,它确实被授予:

当指定 schedule(static, chunk_size) 时,迭代被分成大小为 chunk_size 的块,并且这些块按照线程号的顺序以循环方式分配给团队中的线程。

3.) 对于完全相同范围内的两个 for 循环,每个线程将运行完全相同的迭代

这确实是理所当然的,甚至更普遍:对于具有相同基数的迭代空间的两个循环,将为每个线程提供相同的“逻辑迭代数”。Example A.10.2cOpenMP 3.1 标准应该阐明这一点。

于 2013-09-11T20:20:16.050 回答