我刚刚编写了第一个OpenMP程序,该程序并行化了一个简单的for循环。我在双核机器上运行代码,从1个线程到2个线程时看到了一些加速。但是,我在学校的Linux服务器上运行相同的代码,并没有看到加速。在尝试了不同的事情后,我终于意识到删除一些无用的printf语句会导致代码显着加速。下面是我并行化的代码的主要部分:
#pragma omp parallel for private(i)
for(i = 2; i <= n; i++)
{
printf("useless statement");
prime[i-2] = is_prime(i);
}
我想printf的实现有很大的开销,OpenMP必须与每个线程重复。导致这种开销的原因以及为什么OpenMP无法克服它?
答案 0 :(得分:6)
猜测,但也许stdout被锁定了?
通常,printf是一项昂贵的操作,因为它与其他资源(例如文件,控制台等)交互。
我的实验经验是,Windows控制台上的printf非常慢,在Linux控制台上相对快得多,但如果重定向到文件或/ dev / null则速度最快。
我发现printf-debugging会严重影响我的应用程序的性能,我会谨慎使用它。
尝试将应用程序重定向到文件或/ dev / null,看看是否有任何明显的影响;这将有助于缩小问题所在的范围。
当然,如果printfs没用,为什么它们在循环中呢?
答案 1 :(得分:3)
要扩展@Will的答案......
我不知道stdout是否受到锁定的保护,但我很确定写入它是在软件堆栈中的某个时刻序列化的。包含printf
语句OP可能是对stdout执行大量串行写操作的时间,而不是循环的并行执行。
我建议OP修改printf
语句以包含i
,看看会发生什么。
至于双核机器的明显加速 - 是否具有统计意义?
答案 2 :(得分:1)
这里有一个并行for循环,但调度未指定。
#pragma omp parallel for private(i)
for(i = 2; i <= n; i++)
OpenMP 3.0标准中定义了一些调度类型。可以通过将OMP_SCHEDULE
环境变量设置为type[,chunk]
其中
更改计划类型的另一种方法是调用openmp函数omp_set_schedule
is_prime
功能可以相当快。 /我建议/
prime[i-2] = is_prime(i);
因此,问题可能来自错误的调度模式,当在调度屏障之前执行少量数字时。
printf
里面有2个部分/我认为glibc是流行的Linux libc实现/
printf的第一部分可以并行完成,但第二部分是一个关键部分,它被_IO_flockfile
锁定。
答案 3 :(得分:0)
你的时间是什么 - printf的速度要慢得多吗?在一些紧凑的循环中,printf可能占用总计算时间的很大一部分;例如,如果is_prime()非常快,那么性能更多地取决于对printf的调用次数,而不是对is_prime()的(并行)调用次数。