贡献者: addis
<omp.h>
#pragma omp parallel for
, 如果不是按顺序执行的,就是生效了。
omp_set_num_threads()
(用于 override OMP_NUM_THREADS
环境变量)。注意这里是 “上限”,当 runtime 系统决定用更少的线程效果会更好时,就会这么做。如果不希望是 “上限” 而是严格规定,用 omp_set_dynamic(0)
或者设置环境变量 OMP_DYNAMIC
为 false
。
或者局部地
#pragma omp parallel num_threads(n)
{
#pragma omp for
for () ...
}
omp_get_num_threads()
,这个必须在 parallel 里面执行才不等于 1(例如 parallel for 的内部)
omp_get_thread_num()
#pragma omp parallel
让每个线程执行接下来的一个命令(或者 中所有的命令). 如果 中声明了变量,则每个线程中都有一个同名变量。
#pragma omp parallel
{
#pragma omp for
...
// note implicit barrier after for construct
#pragma omp for
...
}
#pragma omp parallel sections
{
function1();
#pragma omp section
{function2(); function3();}
#pragma omp section
function4();
}
在这个代码中,function1-function4 分别只执行一次,其中被 #pragma omp section
隔开的三个部分允许并行,但 function2() 和 function3() 不允许并行。千万注意两个 section 中不能对同名变量赋值,也就是说同名变量并不会每个线程都复制一份。
现在有一个问题就是如何并行嵌套循环
for (i = 0; i < Nx; ++i)
for (j = 0; j < Ny; ++j)
{}
两个 for 之间没有代码。现在使用的方法是
for (ind = 0; ind < Nx*Ny; ++ind)
{
i = ind/Ny; j = ind%Ny;
...
}
#pragma omp atomic
即可
omp_set_nested(N)
允许 N 重 parallel for 嵌套,默认不允许嵌套($N=0$),只对最外层 parallel for 生效。用 gdb
可以追踪线程的数量。例如以下代码的子函数内的 parallel for 就默认会失效,除非把注释去掉。
void fun(int i)
{
#pragma omp parallel for
for (int j = 0; j < 5; ++j)
cout << "i = " + to_string(i) + ", j = " + to_string(j) + "\n";
}
int main()
{
// omp_set_nested(1);
#pragma omp parallel for
for (int i = 0; i < 5; ++i)
fun(i);
}
当并行时一个或多个命令不是 thread safe 的时候,可以把它放在 critical block 里面,这里面一次只有一个 thread 能进入。
#pragma omp parallel for
for(int i = 0; i < size; i++) {
myArray[i] = i * 2;
#pragma omp critical
{
std::cout << "Processing value: " << myArray[i]
<< " by thread " << omp_get_thread_num() << std::endl;
}
// ...
}
一个更高性能的命令是
#pragma omp atomic
counter++;
若想把每个线程中的一个数加到一起,除了 atomic 也有现成的办法(reduction
):
// sum a 2d array
#pragma omp parallel for reduction(+:s2)
for (Long j = 0; j < a.n1(); ++j) {
const double *p = &a(0, j);
double s = 0;
for (Long i = 0; i < Nr; ++i)
s += p[i];
s2 += s;
}
这种把每个线程中的数据累计到一个数中的过程就叫做 reduction,其他并行计算框架也使用这个词。类似的,还有 reduction(max:my_var)
用于计算最大值。