std::system_clock
和std::steady_clock
有什么区别? (说明不同结果/行为的示例案例会很棒)。
如果我的目标是精确测量函数的执行时间(比如基准),那么std::system_clock
,std::steady_clock
和std::high_resolution_clock
之间的最佳选择是什么?
从N3376:
20.11.7.1 [time.clock.system] / 1:
类
system_clock
的对象表示来自系统范围实时时钟的挂钟时间。
20.11.7.2 [time.clock.steady] / 1:
类
steady_clock
的对象代表时钟,其中time_point
的值从未随着物理时间的推移而减少,并且time_point
的值相对于实时以稳定的速率前进。也就是说,可能无法调整时钟。
20.11.7.3 [time.clock.hires] / 1:
类
high_resolution_clock
的对象代表具有最短刻度周期的时钟。high_resolution_clock
可能是system_clock
或steady_clock
的同义词。
例如,系统范围的时钟可能会受到夏令时等因素的影响,此时在未来某个时间点列出的实际时间实际上可能是过去的时间。 (例如在美国,在下降时间后退一小时,所以同一小时经历“两次”)但是,steady_clock
不允许受这些事情的影响。
在这种情况下,另一种考虑“稳定”的方法是在20.11.3 [time.clock.req] / 2表中定义的要求:
在表59中,
C1
和C2
表示时钟类型。t1
和t2
是由C1::now()
返回的值,其中返回t1
的调用发生在返回t2
的调用之前,并且这两个调用都发生在C1::time_point::max()
之前。 [注意:这意味着C1
没有在t1
和t2
之间缠绕。 - 尾注]表达:
C1::is_steady
返回:const bool
操作语义:true
如果t1 <= t2
总是正确且时钟滴答之间的时间是恒定的,否则false
。
这就是他们的差异所有标准。
如果你想做基准测试,你最好的选择可能是std::high_resolution_clock
,因为你的平台可能会使用高分辨率计时器(例如Windows上的QueryPerformanceCounter
)来制作这个时钟。但是,如果您正在进行基准测试,则应该考虑使用特定于平台的计时器作为基准测试,因为不同的平台会以不同的方式处理这种情况例如,某些平台可能会为您提供一些方法来确定程序所需的实际时钟周期数(与在同一CPU上运行的其他进程无关)。更好的是,让你的手掌握一个真实的探查器并使用它。
Billy根据我完全赞同的ISO C ++标准提供了很好的答案。然而,故事的另一面 - 现实生活。现在看来,在流行编译器的实现中,这些时钟之间确实没有区别:
gcc 4.8:
#ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
...
#else
typedef system_clock steady_clock;
#endif
typedef system_clock high_resolution_clock;
Visual Studio 2012:
class steady_clock : public system_clock
{ // wraps monotonic clock
public:
static const bool is_monotonic = true; // retained
static const bool is_steady = true;
};
typedef system_clock high_resolution_clock;
在gcc的情况下,您可以通过检查is_steady
来检查您是否处理稳定的时钟并相应地表现。然而VS2012似乎在这里作弊:-)
如果您需要高精度时钟,我建议您现在编写符合C ++ 11官方时钟接口的自己的时钟,并等待实现赶上。与在代码中直接使用特定于OS的API相比,这将是更好的方法。对于Windows,您可以这样做:
// Self-made Windows QueryPerformanceCounter based C++11 API compatible clock
struct qpc_clock {
typedef std::chrono::nanoseconds duration; // nanoseconds resolution
typedef duration::rep rep;
typedef duration::period period;
typedef std::chrono::time_point<qpc_clock, duration> time_point;
static bool is_steady; // = true
static time_point now()
{
if(!is_inited) {
init();
is_inited = true;
}
LARGE_INTEGER counter;
QueryPerformanceCounter(&counter);
return time_point(duration(static_cast<rep>((double)counter.QuadPart / frequency.QuadPart *
period::den / period::num)));
}
private:
static bool is_inited; // = false
static LARGE_INTEGER frequency;
static void init()
{
if(QueryPerformanceFrequency(&frequency) == 0)
throw std::logic_error("QueryPerformanceCounter not supported: " + std::to_string(GetLastError()));
}
};
对于Linux来说,它更容易。只需阅读clock_gettime
的手册页并修改上面的代码即可。
GCC 5.3.0实施
C ++ stdlib在GCC源代码中:
high_resolution_clock
是system_clock
的化名system_clock
转发到以下第一个可用的:
clock_gettime(CLOCK_REALTIME, ...)
gettimeofday
time
steady_clock
转发到以下第一个可用的:
clock_gettime(CLOCK_MONOTONIC, ...)
system_clock
然后CLOCK_REALTIME
对CLOCK_MONOTONIC
解释:Difference between CLOCK_REALTIME and CLOCK_MONOTONIC?