C++ 异步与 OpenMP 任务

标签 c++ c++11 asynchronous task openmp

在 OpenMP 中,我可以如下创建一堆任务并使用一些固定数量的线程异步运行它们:

#pragma omp parallel
{
   #pragma omp single 
   {
      for (int i = 0; i < 1000; i++) {
         #pragma omp task
         f(i);
}  }  }

在 C++11 中,我可以做一些不完全相同 std::async:

std::vector<std::future> futures;
for (int i = 0; i < 1000; i++) {
   auto fut = std::async(f, i);
   futures.push_back(std::move(fut));
}
...
for (auto & fut : futures) {
  auto res = fut.get();
  // do something with res
}

我担心的是效率。如果我是正确的,在 OpenMP 中,任务存储在某个任务池中,然后分配给线程(由 OpenMP 运行时自动执行)。

在 C++ 中,在调用 std::async 时,运行时决定是否异步运行 f(i)新线程或将其运行推迟到调用 std::future::get 的点。

因此,无论是运行时

  1. 创建 1000 个线程并同时运行它们,
  2. 或者创建更少的线程,但是随后一些 f(i) 的调用将在主线程中按顺序执行(在最终循环内)。

这两个选项的效率似乎通常低于 OpenMP 所做的(创建许多任务并在固定数量的线程中同时运行它们)。

有什么方法可以获得与 OpenMP 任务为 C++ 线程提供的行为相同的行为吗?

更新

我用以下代码做了一些测量:https://wandbox.org/permlink/gLCFPr1IjTofxwQh在使用 GCC 7.2 和 -O2 编译的 12C Xeon E5 CPU 上:

  1. 12 个线程的 OpenMP 运行时间:12.2 [s]
  2. C++ 线程运行时:12.4 [s]

(几次运行的平均值)。它们看起来几乎是一样的。

但是,我也对 500,000 个任务 (n) 和其中的 1,000 次迭代 (m) 进行了相同的尝试,然后时间出现了显着差异:

  1. 12 个线程的 OpenMP 运行时间:15.1 [s]
  2. C++ 线程运行时:175.6 [s]

更新 2

我测量了创建新线程的次数(按照此答案插入pthread_create 调用:https://stackoverflow.com/a/3709027/580083):

第一个实验(20,000 个任务,其中 20,000 次迭代):

  1. 具有 12 个线程的 OpenMP 运行时:11
  2. C++ 线程运行时:20,000

第二个实验(500,000 个任务,其中 1,000 次迭代):

  1. 具有 12 个线程的 OpenMP 运行时:11
  2. C++ 线程运行时:32,744

最佳答案

你分析的很好,但我认为std::async中的线程池存在漏洞.

OpenMP 确实使用固定的、用户控制的线程数量来非常灵活地执行任务。 untied任务甚至可以在线程之间移动,尽管 doesn't seem to be well-supported in practice .

是的,根据 C++11 标准,实现必须选择 std::launch::asyncstd::launch::deferred .前者must create a std::thread object ,而后者将在调用 wait 的线程中执行任务代码.但是,标准留下了注释(强调我的):

If this policy is specified together with other policies, such as when using a policy value of launch::async | launch::deferred, implementations should defer invocation or the selection of the policy when no more concurrency can be effectively exploited.

老实说,看不出除了该注释之外的标准措辞如何允许实现推迟决定 - 但该标准似乎实际上鼓励线程池!如果决定选择launch:async被推迟,这意味着所需的新 std::thread可以重用现有的执行线程 - 至少我不明白为什么不这样做。

本来我以为std::thread也可以实现为绿色线程,这也意味着线程池。但是,线程 [由 <thread> 管理] 的标准说明] 旨在与操作系统线程一对一映射。

在一天结束时测量以验证您的表现。可能有一个非常糟糕的 OpenMP 实现或一个非常聪明的标准库实现。

This answer to a similar question , 显示一些测量结果表明 std::async 的高开销并共享测量代码。

关于C++ 异步与 OpenMP 任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47895048/

相关文章:

c++ - Eclipse-CDT/C++ : Undefined reference-errors although right . o 文件被创建并传递给链接器

c++ - 如何禁止赋值

c++ - 使用模板参数包代替宏

javascript - Jasmine beforeEach 不等待完成回调

c - 如何绕过已连接的聚会

c# - 在c#中使用async和await时UI将被阻塞

c++ - 嵌入式环境中的STL

c++ - openframeworks - 如何淡入淡出视频

c++ - 为什么 memcpy() 和 memmove() 比指针增量快?

c++ - 在 C++ 中加速双绝对值