c – 对OpenMP中静态调度开销的影响

我想到哪些因素会影响OpenMP中的静态调度开销.
在我看来,它受到以下因素的影响:

> CPU性能
> OpenMP运行时库的具体实现
>线程数

但是我错过了其他因素吗?也许任务的大小,……?

此外:开销是否线性地依赖于迭代次数?
在这种情况下,我希望有静态调度和4个内核,开销随着4 * i次迭代线性增加.到目前为止正确吗?

编辑:
我只对静态(!)调度开销感兴趣.我不是在谈论线程启动开销和在同步和关键部分开销上花费的时间.

解决方法:

您需要将OpenMP的开销分开,以创建一个团队/线程池,以及每个线程在for循环中操作单独的迭代器集合的开销.

静态调度很容易手工实现(有时非常有用).让我们考虑一下我认为最重要的两个静态调度计划(静态)和计划(静态,1),然后我们可以将其与计划(动态,块)进行比较.

#pragma omp parallel for schedule(static)
for(int i=0; i<N; i++) foo(i);

相当于(但不一定等于)

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

#pragma omp parallel for schedule(static,1)
for(int i=0; i<N; i++) foo(i);

相当于

#pragma omp parallel 
{
    int ithread = omp_get_thread_num();
    int nthreads = omp_get_num_threads();
    for(int i=ithread; i<N; i+=nthreads) foo(i);
}

由此可以看出,实现静态调度非常简单,因此开销可以忽略不计.

另一方面,如果你想手动实现时间表(动态)(与schedule(dynamic,1)相同),那就更复杂了:

int cnt = 0;
#pragma omp parallel
for(int i=0;;) {
    #pragma omp atomic capture
    i = cnt++;
    if(i>=N) break;
    foo(i);                                    
}

这需要OpenMP> = 3.1.如果你想用OpenMP 2.0(对于MSVC)这样做,你需要像这样使用critical

int cnt = 0;
#pragma omp parallel
for(int i=0;;) {
    #pragma omp critical   
    i = cnt++;
    if(i>=N) break;
    foo(i);
} 

这相当于schedule(动态,块)(我没有使用原子访问优化它):

int cnt = 0;
int chunk = 5;
#pragma omp parallel
{
    int start, finish;
    do {
        #pragma omp critical
        {
            start = cnt;
            finish = cnt+chunk < N ? cnt+chunk : N;
            cnt += chunk;
        }
        for(int i=start; i<finish; i++) foo(i);
    } while(finish<N);
}

显然,使用原子访问会导致更多的开销.这也说明了为什么使用较大的块进行调度(动态,块)可以减少开销.

上一篇:mybatis plus 查询语句


下一篇:Python中的快速方法调用调度