什么是std::system_clock
和std::steady_clock
之间的区别?(一个展示不同结果/行为的例子将会很好)。
如果我的目标是精确测量函数执行时间(如基准测试),在std::system_clock
,std::steady_clock
和std::high_resolution_clock
之间,哪个是最好的选择?
什么是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
操作语义:如果t1 <= t2
始终为真且时钟滴答声之间的时间是恒定的,则返回true
,否则返回false
。这就是标准对它们的区别的全部内容。
如果您想进行基准测试,您最好使用
std::high_resolution_clock
,因为您的平台可能会为此时钟使用高分辨率计时器(例如Windows上的QueryPerformanceCounter
)。但是,如果您进行基准测试,应该考虑使用特定于平台的计时器进行基准测试,因为不同的平台处理这个问题的方式不同。例如,某些平台可能会为您提供一些确定程序所需的实际时钟滴答数的手段(独立于在同一CPU上运行的其他进程)。更好的选择是使用真正的分析工具。
steady_clock
和system_clock
之间存在差异。 - Billy ONealsystem_clock
必须是UTC。 - Billy ONealBilly基于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官方时钟接口的自己的时钟,并等待实现跟进。这将比直接在代码中使用特定于操作系统的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
的 man 页面并修改上面的代码即可。
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?
high_resolution_clock
是std::chrono中steady_clock
的别名,而steady_clock
使用QueryPerformanceCounter
和QueryPerformanceFrequency
。(适用于Visual Studio 2015和(可能)更高版本) - starriet相关的关于chrono的演讲,演讲人是Howard Hinnant,也是chrono
的作者:
不要使用high_resolution_clock
,因为它是以下某一项的别名之一:
system_clock
: 它像一个普通的时钟,用于处理与时间/日期相关的事情steady_clock
: 它就像一个秒表,用于计时。或许最重要的不同之处就是,std::chrono:system_clock
的起始点是1970年1月1日被称为UNIX纪元时间。
而对于std::chrono::steady_clock
来说,它通常是您个人电脑的启动时间,因此非常适合用于测量间隔。
system_clock
只会在C++标准试图适应的幻想计算机上是不稳定的。问题是,system_clock
映射到std::time_t
值(C语言风格的时间),而我不知道任何平台(至少不包括非外来或古老的平台)的Cstd::time()
函数不是与POSIX时间相同。而POSIX时间根据定义是“稳定的”。 - Charles Salviasystem_clock
在 Windows 上并不稳定。在Windows上,系统时间可能会被任何具备足够特权的用户更改为任意值。此外,时间同步服务可能会根据需要将系统时间向后调整。我预计大多数其他平台都有类似的功能允许调整系统时间。 - James McNellis