omp_get_max_threads() 在并行区域返回 1,但应该是 8

Posted

技术标签:

【中文标题】omp_get_max_threads() 在并行区域返回 1,但应该是 8【英文标题】:omp_get_max_threads() returns 1 in parallel region, but it should be 8 【发布时间】:2017-08-02 22:39:05 【问题描述】:

我正在 Linux 上编译一个复杂的 C++ 项目,该项目使用 OpenMP,使用 CMake 和 GCC 7 编译。 我在这个特定项目中遇到的奇怪问题是 OpenMP 显然在工作,但它认为只支持 1 个线程,而应该是 8 个。但是,如果我手动指定线程数,它确实会加速代码。

logOut << "In parallel? " << omp_in_parallel() << std::endl;
logOut << "Num threads = " << omp_get_num_threads() << std::endl;
logOut << "Max threads = " << omp_get_max_threads() << std::endl;

logOut << "Entering my parallel region: " << std::endl;

//without num_threads(5), only 1 thread is created
#pragma omp parallel num_threads(5) 
            
      #pragma omp single nowait
      
          logOut << "In parallel? " << omp_in_parallel() << std::endl;
          logOut << "Num threads = " << omp_get_num_threads() << std::endl;
          logOut << "Max threads = " << omp_get_max_threads() << std::endl;
      
  

输出:

[openmp_test] In parallel? 0
[openmp_test] Num threads = 1
[openmp_test] Max threads = 1
[openmp_test] Entering my parallel region: 
[openmp_test] In parallel? 1
[openmp_test] Num threads = 5
[openmp_test] Max threads = 1

更奇怪的是,一个简单的测试 OpenMP 程序直接正确地报告了并行区域内部和外部的最大线程数为 8。 我一直在梳理所有的 CMake 文件,试图找出为什么这个项目表现不同的任何迹象,但到目前为止我什么也没发现。在我的任何项目文件中都没有提到omp_set_num_threads,我可以确认没有声明OMP_NUM_THREADS。此外,当我在 Windows 上使用 MSVC 编译同一个项目时,这个问题从未发生过。

任何想法可能是什么问题?

(编辑:我扩展了代码示例以表明它不是嵌套的并行块)

CPU:Intel(R) Core(TM) i7-6700K

操作系统:Manjaro Linux 17.0.2

编译器:GCC 7.1.1 20170630

_OPENMP = 201511(我猜这意味着 OpenMP 4.5)

【问题讨论】:

您能否在您的问题中添加特定的平台信息(操作系统、硬件、编译器、OpenMP 运行时等)?您还可以尝试在并行区域之前输出omp_in_parallel()omp_get_num_threads() 吗?您还可以验证 OMP_NUM_THREADS 在您的环境中未设置吗?如果你设置它,你会观察到不同的行为吗? 谢谢,我已经添加了你建议的信息。我确认并行区域外的代码不在并行区域中,并且没有声明OMP_NUM_THREADS 您能否尝试在程序的开头添加从 getenv("OMP_NUM_THREADS"); 的调用以确保它返回 NULL?此外,您能否扩展您的代码 sn-p 以使其完整(即,就像 @FlashMcQueen 如何将其包装在 main() 中一样),并确认相同的行为?这将帮助我们排除一些干扰线程的库。 getenv("OMP_NUM_THREADS") 为空。至于“完整的sn-p”,我已经提到过这个问题不会出现在一个只测试OpenMP的简单命令行程序中。更重要的是,在运行之前设置 OMP_NUM_THREADS 没有任何效果。我想这意味着问题来自第三方库? 另外,在环境中设置OMP_NUM_THREADS不会影响omp_get_max_threads 【参考方案1】:

您在并行区域内看到的值似乎是正确的(假设 OMP_NESTED 不正确)。 omp_get_max_threads() 返回如果您要从当前线程并行运行时可能获得的最大线程数。由于您已经在一个并行区域内(并且我们假设嵌套并行性被禁用),这将是一个。

3.2.3 omp_get_max_threads

总结 omp_get_max_threads 例程返回可以使用的线程数的上限 如果没有 num_threads 的并行构造,则组建一个新团队 从该例程执行返回后遇到子句。

不过,这并不能解释为什么您会在并行区域之外看到值 1。 (但它确实回答了标题中的问题,答案是“一个是正确的答案”)。

【讨论】:

【参考方案2】:

您的程序的行为与之前调用 omp_set_num_threads(1) 完全相同。

考虑到这个sn-p:

#include <iostream>
#include <string>
#include <vector>
#include "omp.h"
int main() 

omp_set_num_threads(1);

std::cout << "before parallel section: " << std::endl;
std::cout << "Num threads = " << omp_get_num_threads() << std::endl;
std::cout << "Max threads = " << omp_get_max_threads() << std::endl;

//without num_threads(5), only 1 thread is created
#pragma omp parallel num_threads(5) 
            
      #pragma omp single
      
          std::cout << "inside parallel section: " << std::endl;
          std::cout << "Num threads = " << omp_get_num_threads() << std::endl;
          std::cout << "Max threads = " << omp_get_max_threads() << std::endl;
      
  

  return 0;

输出是

before parallel section: 
Num threads = 1    
Max threads = 1
inside parallel section:  
Num threads = 5
Max threads = 1

当我通过将线程数设置为 4 而不是 1(在您的机器上为 8)来运行它时,输出与预期的一样:

before parallel section: 
Num threads = 1
Max threads = 4
inside parallel section: 
Num threads = 5
Max threads = 4

您是否尝试在代码开头调用 omp_set_num_threads(8)?或者您是否在程序之前将线程数设置为 1(例如通过在函数内部调用 this...)?

另一种解释可能是,openMP API 认为没有必要拥有多个线程,因为在并行部分中只实现了一个部分。在这种情况下,尝试添加一些可以由多个线程执行的代码以更快地运行(即递增大型整数数组的所有值或调用 omp_get_thread_num())在单个部分之外但在并行部分和线程数内应该不同。调用 omp_set_num_threads 只是设置使用线程数的上限。

【讨论】:

这是有道理的,但到底有什么可以打电话给omp_set_num_threads?我做了一个完整的搜索,它没有出现在我的代码中。 然后,如果您确定没有调用 omp_set_num_threads(1),请尝试在单个部分之外和并行部分内添加 omp_get_thread_num。 (第二种解释) 已经试过了。如果不手动设置 num_threads,omp_get_thread_num 始终为 0。 在 pragma omp 单节外嗡嗡作响,这很奇怪

以上是关于omp_get_max_threads() 在并行区域返回 1,但应该是 8的主要内容,如果未能解决你的问题,请参考以下文章

在JAVA中并行和并发机制的区别?

Stream并行流详解

Oracle“并行执行”之二——并行执行类型

在 OpenMP 并行代码中,memset 并行运行有啥好处吗?

R Snowfall - 在并行函数中调用并行函数?

在SQL语句中用PARALLEL指定并行查询,应该怎么用