1

假设我有一个包含 n 个元素和 n_threads 的向量。我想使用#pragma omp parallel这样的方式,每个线程接收 n / n_threads 块大小,最后一个取决于具体情况。

#include <stdio.h>
#include <omp.h>

int main()
{

    int *v = malloc ( n * sizeof(int) );

    #pragma omp parallel for (what should i put here?)
    for(i = 0; i < n; ++i)
    {
        ++v[i];
    }
    return 0;
}

例如:n = 10003,n_threads = 4

  • thread_0 应该得到 2500 个块
  • thread_1 应该得到 2500 个块
  • thread_2 应该得到 2500 个块
  • thread_3 应该得到 2503 个块
4

2 回答 2

3

简而言之 - 你不能那样做。您所能做的就是在schedule(static)不指定块大小的情况下指定子句,OpenMP 运行时会将迭代计数划分为大致相同大小的块。具体怎么做取决于实施。这就是 OpenMP 标准对静态调度的描述:

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

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

对于 n = 10003 和 n_threads = 4,您可以指定块大小为 2500,迭代空间将被划分为大小为 2500、2500、2500、2500 和 3 的块,它们将被分配到线程 0、1、2、3和 0。因此线程 0 将获得 2503 次迭代,但它们在迭代空间中不会是连续的。如果您不指定块大小,则由实现决定向哪个线程提供额外的迭代。

于 2012-05-12T13:15:10.997 回答
0

据我所知,OpenMP 不能保证确切的块大小,但自己计算它们并不难。这是一些示例代码:

#include <stdio.h>
#include <omp.h>

int main(void) {

  int n = 10003;
  int n_threads = 4;
  int chunk_size = n / n_threads;

  #pragma omp parallel num_threads(n_threads)
  {
    int id = omp_get_thread_num();
    int b = id * chunk_size;
    int e = id == n_threads - 1 ? n : b + chunk_size;
    printf("thread %d: %d items\n", id, e - b);
    for (int i = b; i < e; i++) {
      // process item i
    }
  }

  return 0;
}

样本输出:

thread 0: 2500 items
thread 1: 2500 items
thread 3: 2503 items
thread 2: 2500 items

请注意: “每个线程获取 n / n_threads 个项目,最后一个项目”的策略对于您提供的数字来说很好,但在其他情况下可能会导致工作共享效率非常低。例如,对于 60 个项目和 16 个线程,此公式将为所有线程提供 3 个项目 - 除了最后一个,它将获得 15 个项目。如果处理每个项目的时间大致相同,这意味着整个过程所需的时间大约是必要时间的四倍,并且大多数 CPU 内核大部分时间都处于空闲状态。我认为只有在有充分理由需要以这种方式分配工作时才应使用此公式。否则,OpenMP 选择的块大小可能会更好。

于 2018-10-30T22:24:53.730 回答