在 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
的点。
因此,无论是运行时
- 创建 1000 个线程并同时运行它们,
- 或者创建更少的线程,但是随后一些
f(i)
的调用将在主线程中按顺序执行(在最终循环内)。
这两个选项的效率似乎通常低于 OpenMP 所做的(创建许多任务并在固定数量的线程中同时运行它们)。
有什么方法可以获得与 OpenMP 任务为 C++ 线程提供的行为相同的行为吗?
更新
我用以下代码做了一些测量:https://wandbox.org/permlink/gLCFPr1IjTofxwQh在使用 GCC 7.2 和 -O2
编译的 12C Xeon E5 CPU 上:
- 12 个线程的 OpenMP 运行时间:12.2 [s]
- C++ 线程运行时:12.4 [s]
(几次运行的平均值)。它们看起来几乎是一样的。
但是,我也对 500,000 个任务 (n
) 和其中的 1,000 次迭代 (m
) 进行了相同的尝试,然后时间出现了显着差异:
- 12 个线程的 OpenMP 运行时间:15.1 [s]
- C++ 线程运行时:175.6 [s]
更新 2
我测量了创建新线程的次数(按照此答案插入pthread_create
调用:https://stackoverflow.com/a/3709027/580083):
第一个实验(20,000 个任务,其中 20,000 次迭代):
- 具有 12 个线程的 OpenMP 运行时:11
- C++ 线程运行时:20,000
第二个实验(500,000 个任务,其中 1,000 次迭代):
- 具有 12 个线程的 OpenMP 运行时:11
- C++ 线程运行时:32,744
最佳答案
你分析的很好,但我认为std::async
中的线程池存在漏洞.
OpenMP 确实使用固定的、用户控制的线程数量来非常灵活地执行任务。 untied
任务甚至可以在线程之间移动,尽管 doesn't seem to be well-supported in practice .
是的,根据 C++11 标准,实现必须选择 std::launch::async
或 std::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 oflaunch::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/