【发布时间】:2018-08-26 14:53:33
【问题描述】:
假设我有很多计算要在多个线程中运行(以及基准 CPU 时间)。作为一个玩具示例:
#include <chrono>
#include <future>
#include <iostream>
#include <vector>
using unit_t = std::chrono::nanoseconds;
unit_t::rep expensive_computation() {
auto start = std::chrono::steady_clock::now();
// Something time-consuming here...
auto end = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<unit_t>(end - start).count();
return duration;
}
int main() {
std::vector<std::future<unit_t::rep>> computations;
for (int i = 0; i < 100; i++) {
computations.push_back(std::async(expensive_computation));
}
for (size_t i = 0; i < computations.size(); i++) {
auto duration = computations[i].get();
std::cout << "#" << i << " took " << duration << "ns" << std::endl;
}
}
我担心因为steady_clock is montonic across threads 基础时钟按进程而不是每个线程滴答(如果安排了任何线程,则时钟滴答为所有 线程)。这意味着如果一个线程正在休眠,steady_clock 仍会为它打勾,而这一次将错误地包含在该线程的duration 中。我的怀疑正确吗?还是steady_clock 仅针对线程内的线程 CPU 时间打勾?
换一种说法,这种方法是否是一种独立计时大量计算的安全方法(这样在一个线程上花费的 CPU 时间不会影响另一个线程的duration)?或者我是否需要为每个计算分离单独的进程以使 steady_clock 仅在计算运行/计划时打勾?
编辑:我也认识到,与内核相比,旋转更多的线程可能是解决此问题的低效方法(尽管我并不特别关心计算吞吐量;此外,我只想要它们作为一个小组以最快的时间完成)。我怀疑在实践中,我需要维护一个小常数的有界线程列表(比如限制在核心数量),并且只有在核心可用时才开始新的计算。但是,这不应该对我上面关心的时间产生影响;它应该只影响挂钟时间。
【问题讨论】:
-
我认为您应该在 100% 空闲的机器上进行测量。在这种情况下,您使用哪个时钟并不重要(如果您在加载的机器上测量事物,即使您测量线程时间,您的基准也可能不准确:超线程、缓存使用等可能会影响结果)。跨度>
-
未来就绪检查应该在 future.get() 之前改进代码。在 ns 分辨率(也是 CPU 域)下,检查系统的最小分辨率可能是必不可少的。
-
@geza 这是一个很好的观点。我目前正在努力保护这样的环境。即使在 100% 空闲的机器上,我也会担心的一个问题是,某些计算比其他计算花费的时间要长得多(这些计算可能会受到负载的更大影响,可能会人为地增加它们的时间)。但我怀疑这在很大程度上是不可避免的。
-
@seccpur 您所说的“未来就绪检查”是什么意思?
future.get()不打电话给future.wait()吗?在玩具示例中,我并不特别关心结果的延迟(只是整体运行时间)。此外,ns 分辨率是这是一个玩具示例的产物。我真正的基准分辨率可能是微秒或毫秒。 -
@BaileyParker:“即使在 100% 空闲的机器上,我也会担心一些计算比其他计算花费的时间要长得多”。你这是什么意思? (请注意:记得关闭 CPU 频率缩放)。
标签: c++ multithreading std future chrono