我正在使用OpenMP并行执行大型循环。假设我正在处理的数组总共有N个条目。我希望一个线程执行前N / 2个条目,另一个线程执行最后一个N / 2。
我必须避免线程处理彼此相邻的条目。大小N总是比线程数大得多,所以我不需要担心锁定,如果我可以让OpenMP以我上面概述的方式分配工作。
如果在编译时知道大小N,我可以使用#pragma omp parallel for schedule(static,N/2)
。不幸的是它不是。那么,我该如何动态定义块大小呢?
答案 0 :(得分:4)
只要N在运行时已知,就没有问题;我不确定为什么你认为它必须在编译时知道。如果在编译时必须知道所有内容,那么OMP循环结构的用途非常有限。
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
int main(int argc, char **argv) {
int n;
int chunksize;
if (argc != 2) {
fprintf(stderr,"Usage: %s n, where n = number of iterations.\n", argv[0]);
exit(-1);
}
n = atoi(argv[1]);
if (n<1 || n>200) n = 10;
chunksize = n/2;
#pragma omp parallel num_threads(2) default(none) shared(n,chunksize)
{
int nthread = omp_get_thread_num();
#pragma omp for schedule(static,chunksize)
for (int i=0; i<n; i++) {
printf("Iter %d being done by thread %d\n", i, nthread);
}
}
return 0;
}
它运行得足够简单,如此:
$ gcc -v
[...]
gcc version 4.4.0 (GCC)
$ gcc -o loop loop.c -fopenmp
$ ./loop 10
Iter 5 being done by thread 1
Iter 6 being done by thread 1
Iter 7 being done by thread 1
Iter 8 being done by thread 1
Iter 9 being done by thread 1
Iter 0 being done by thread 0
Iter 1 being done by thread 0
Iter 2 being done by thread 0
Iter 3 being done by thread 0
Iter 4 being done by thread 0
答案 1 :(得分:2)
如果你不想像@Jonathan Dursi's answer那样使用内置的openmp调度选项,那么你可以自己实现所需的选项:
#include <stdio.h>
#include <omp.h>
/* $ gcc -O3 -fopenmp -Wall *.c && ./a.out */
static void doloop(int n) {
int thread_num, num_threads, start, end, i;
#pragma omp parallel private(i,thread_num,num_threads,start,end)
{
thread_num = omp_get_thread_num();
num_threads = omp_get_num_threads();
start = thread_num * n / num_threads;
end = (thread_num + 1) * n / num_threads;
for (i = start; i != end; ++i) {
printf("%d %d\n", thread_num, i);
}
}
}
int main() {
omp_set_num_threads(2);
doloop(10);
return 0;
}
0 0
0 1
0 2
0 3
0 4
1 5
1 6
1 7
1 8
1 9
答案 2 :(得分:0)
我在dotNET上遇到了类似的问题,最后编写了一个智能队列对象,一旦可用,就会一次返回十几个对象。一旦我掌握了一个软件包,我就决定一个可以一次处理所有这些软件的线程。
在处理这个问题时,我记住W队列比M队列更好。最好有一个长行与多个工人,而不是每个工人有一条线。