3

我刚刚编写了我的第一个 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 不能克服它?

4

4 回答 4

6

推测,但也许标准输出由锁保护?

一般来说,printf 是一项昂贵的操作,因为它与其他资源(例如文件、控制台等)交互。

我的经验是 printf 在 Windows 控制台上非常慢,在 Linux 控制台上相对快得多,但如果重定向到文件或 /dev/null 仍然最快。

我发现 printf-debugging 会严重影响我的应用程序的性能,所以我很少使用它。

尝试运行重定向到文件或 /dev/null 的应用程序,看看这是否有任何明显的影响;这将有助于缩小问题所在。

当然,如果 printfs 没用,那它们为什么还要循环呢?

于 2010-04-26T06:30:07.203 回答
3

要扩展@Will的答案...

我不知道标准输出是否受到锁的保护,但我很确定对它的写入在软件堆栈中的某个点被序列化。使用printf包含的语句,OP 可能正在计时执行大量串行写入到标准输出,而不是循环的并行执行。

我建议 OP 将printf语句修改为 include i,看看会发生什么。

至于双核机器上的明显加速——它是否具有统计学意义?

于 2010-04-26T06:45:29.357 回答
1

您在这里有一个并行的 for 循环,但未指定调度。

#pragma omp parallel for private(i)
for(i = 2; i <= n; i++)

OpenMP 3.0 标准中定义了一些调度类型。可以通过将OMP_SCHEDULE环境变量设置为type[,chunk]where来更改它们

  • typestaticdynamicguidedauto之一
  • chunk是一个可选的正整数,用于指定块大小

另一种更改计划类型的方法是调用 openmp 函数omp_set_schedule

is_prime功能可以相当快。/我建议/

  prime[i-2] = is_prime(i);

因此,问题可能来自错误的调度模式,即在调度障碍之前执行了少量数字。

里面printf有两个部分/我认为 glibc 是流行的 Linux libc 实现/

  1. 解析格式字符串并将所有参数放入缓冲区
  2. 将缓冲区写入文件描述符(写入文件缓冲区,因为标准输出默认由 glibc 缓冲)

printf 的第一部分可以并行完成,但第二部分是关键部分,它被锁定_IO_flockfile

于 2010-12-29T08:02:38.517 回答
0

您的时间安排是什么- printf 的速度要慢得多吗?在一些紧凑的循环中,printf 可能会占用总计算时间的很大一部分;例如,如果 is_prime() 非常快,因此性能更多地取决于对 printf 的调用次数,而不是对 is_prime() 的(并行)调用次数。

于 2010-12-26T15:49:07.360 回答