105

std::system_clock和 和有什么不一样std::steady_clock?(说明不同结果/行为的示例案例会很棒)。

std::system_clock如果我的目标是精确测量函数的执行时间(如基准测试) ,那么std::steady_clock和之间的最佳选择是std::high_resolution_clock什么?

4

5 回答 5

77

从 N3376:

20.11.7.1 [time.clock.system]/1:

类对象system_clock代表系统范围实时时钟的挂钟时间。

20.11.7.2 [时间.时钟.稳定]/1:

类对象steady_clock表示时钟,其值time_point永远不会随着物理时间的推移而减少,并且其值以time_point相对于实时的稳定速率前进。也就是说,时钟可能不会被调整。

20.11.7.3 [time.clock.hires]/1:

类对象high_resolution_clock表示具有最短滴答周期的时钟。high_resolution_clock可能是system_clockor的同义词steady_clock

例如,系统范围的时钟可能会受到夏令时之类的影响,此时列出的未来某个时间点的实际时间实际上可能是过去的时间。(例如在美国,秋天的时间向后移动一小时,因此同一小时会经历“两次”)但是,steady_clock不允许受此类事情的影响。

在这种情况下考虑“稳定”的另一种方式是在 20.11.3 [time.clock.req]/2 的表中定义的要求中:

在表 59中C1C2表示时钟类型。t1并且t2C1::now()调用返回t1发生在调用返回之前的位置返回的值t2,并且这两个调用都发生在之前C1::time_point::max()。[注意:这意味着没有在和C1之间环绕。——尾注] t1t2

表达式:C1::is_steady
返回:const bool
操作语义:trueift1 <= t2始终为真并且时钟滴答之间的时间是恒定的,否则false.

这就是标准对它们的差异的全部内容。

如果您想进行基准测试,最好的选择可能是,因为您的平台很可能为此时钟std::high_resolution_clock使用高分辨率计时器(例如在 Windows 上)。QueryPerformanceCounter但是,如果您要进行基准测试,您应该真正考虑使用特定于平台的计时器来进行基准测试,因为不同的平台对此的处理方式不同。例如,某些平台可能会为您提供一些方法来确定程序所需的实际时钟滴答数(独立于在同一 CPU 上运行的其他进程)。更好的是,得到一个真正的分析器并使用它。

于 2012-11-07T04:54:57.180 回答
47

Billy 根据我完全同意的 ISO C++ 标准提供了一个很好的答案。然而,故事还有另一面——现实生活。现在看来,在流行编译器的实现中,这些时钟之间确实没有区别:

海合会 4.8:

#ifdef _GLIBCXX_USE_CLOCK_MONOTONIC
   ...
#else
  typedef system_clock steady_clock;
#endif
  typedef system_clock high_resolution_clock;

视觉工作室 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;

is_steady在 gcc 的情况下,您可以通过检查和相应的行为来检查您是否处理稳定的时钟。但是 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并修改上面的代码。

于 2012-11-07T09:13:17.257 回答
20

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_REALTIMEvsCLOCK_MONOTONIC解释在:CLOCK_REALTIME 和 CLOCK_MONOTONIC 之间的区别?

于 2016-12-17T21:56:49.087 回答
5

Howard Hinnant 的相关谈话,作者chrono

不要使用high_resolution_clock,因为它是其中之一的别名:

  • system_clock:它就像一个普通的时钟,用于时间/日期相关的东西
  • steady_clock: 它就像一个秒表,用来计时。
于 2020-09-28T02:43:33.083 回答
4

也许,最显着的区别在于,起点std::chrono:system_clock是 1.1.1970,即所谓的 UNIX 时代。另一方面,std::chrono::steady_clock通常用于 PC 的启动时间,它最适合测量间隔。

于 2019-10-31T17:08:58.093 回答