【问题标题】:Precision of std::chrono::system_clock vs std::chrono::steady_clock across C++ implementations?跨 C++ 实现的 std::chrono::system_clock 与 std::chrono::steady_clock 的精度?
【发布时间】:2019-02-18 06:53:17
【问题描述】:

以下程序:

#include <chrono>
#include <iostream>
#include <vector>

inline uint64_t now() {
    return std::chrono::duration_cast
       <std::chrono::nanoseconds> 
       (std::chrono::system_clock::now()
          .time_since_epoch())
       .count();
}

int main() {
        std::vector<uint64_t> v;
        for (int i = 0; i < 1000; i++)
                v.push_back(now());

        for (int i = 0; i < v.size()-1; i++)
                std::cout << v[i+1] - v[i] << std::endl;
}

在 250 到 300 范围内打印数字:

g++ (Ubuntu 8.2.0-7ubuntu1) 8.2.0

与:

Linux 4.18.0-15-generic #16-Ubuntu SMP x86_64 x86_64 x86_64 GNU/Linux

意思是 std::chrono::system_clock 在这个系统上是纳秒精度(很可能是 gettimeofday 对吧?)。我有几个问题:

  1. 在这个系统上std::chrono::system_clockstd::chrono::steady_clock 有什么区别? (是的,我知道它们在标准中的规定不同,我正在考虑这个实现。)

  2. 所有 libstdc++ 目标的答案是否相同?

  3. 所有 libc++ 目标的答案是否相同?

  4. Windows/MSVC 目标上的答案是否相同?

【问题讨论】:

    标签: c++ c++17 chrono


    【解决方案1】:

    我不确定你问的是你想要回答的问题。我看到的一件事是您询问稳定时钟和系统时钟之间的差异,就其精度而言。第二个,单从sn-p来看,是关于system_clock::now、duration_cast、vector::push_back/vector::insert和(隐式)vector::resize的性能。

    如果你不介意,我会尝试回答这两个中的第一个:

    • 这些时钟的关键在于,一个 (system_clock) 适合与任何物理日历互操作,因此有时可以返回(夏季/冬季时间转换当某人或某事更改系统时机器上的时间,请参阅Difference between std::system_clock and std::steady_clock?),而另一个 (steady_clock) 保证只会向前运行,并且适用于例如测量 push_back 的长度。
    • 无法保证这些时钟的分辨率。这就是为什么你应该尽可能长地保持时钟的持续时间类型,并且只在打印之前使用 .count() 访问器;但是,由于无法保证所使用的期限,您可能应该要么
      1. 对稳定的东西执行 duration_cast,
      2. 或执行一些花哨的后缀选择,将句点用作某些元程序的参数。
    • 无法保证 time_since_epoch() 的含义,并且在 C++20 之前,无法比较属于两个不同时钟的 time_points/durations
    • 并且,请记住,对于任何系统上的任何时钟的周期分辨率都没有任何保证;我发现了困难的方法(编写一些花哨的模板),甚至不能保证周期可以被 1000 整除...对于其中一个时钟,其中一个库使用 1 超过 10^8 作为周期.. .

    因此,不建议询问任何特定的实现并希望它们的常量也将用于其他实现(即使对于同一供应商)是不可取的。我总是尝试使用时钟的::time_point 或它的 ::duration,或者,作为最后的手段,毫秒或纳秒,这取决于我要测量什么以及所测量的东西的飞行速度。

    另外请注意,有 system_clock::(to/from)_time_t() 函数,即使 system_clock::duration 有更精细的周期,它肯定会产生 1 比 1 的值(秒)。

    修改后的 sn-p,使用 stable_clock,它的 time_point 并尽可能晚地调用 duration_cast 将是:

    #include <chrono>
    #include <iostream>
    #include <vector>
    
    int main() {
            using namespace std::chrono;
            using clock = steady_clock;
    
            std::vector<clock::time_point> v;
            for (int i = 0; i < 1000; i++)
                    v.push_back(clock::now());
    
            for (size_t i = 0; i < v.size()-1; i++) {
                    std::cout
                            << duration_cast<nanoseconds>(
                                    v[i+1] - v[i]
                                    ).count()
                            << "ns\n";
            }
    }
    

    编辑:哦,另一件事是原始代码中没有任何内容可以证明您的库使用 nano 作为 system_clock 中的句点。你正在做一个 duration_cast (如果必须的话,它使用整数除法)并从中获取周期,但持续时间不同,比如 duration_cast>,你也可以在下面的某个地方得到非零最低的 1000。不太可能,但可能永远不会少。

    编辑 2:复杂的。更改了第一个要点中 system_clock 不稳定的原因。

    【讨论】:

    • 你是说我代码中的now()函数可以倒退吗?自UTC时代以来,它不会返回纳秒,这不受(例如)日光节约时间的影响?什么情况下会倒退?
    • 是的,它可以倒退,但(可能)不是因为我给出的原因。当用户可以更改系统中的时钟时, system_clock 将反映这一点并转到任何新的 time_point 现在是当前的,但 stable_clock 仍将返回一些其他时间源(可能是正常运行时间,但这也没有定义,至少不在 C++17 中)。更新了答案以删除时区跳跃并将另一个答案与更好的解释联系起来。
    猜你喜欢
    • 2014-03-23
    • 2017-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多