C++ 实现中 std::chrono::system_clock 与 std::chrono::steady_clock 的精度?

And*_*zos 2 c++ c++-chrono c++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;
}
Run Code Online (Sandbox Code Playgroud)

在以下位置打印大约 250 到 300 范围内的数字:

g++ (Ubuntu 8.2.0-7ubuntu1) 8.2.0
Run Code Online (Sandbox Code Playgroud)

和:

Linux 4.18.0-15-generic #16-Ubuntu SMP x86_64 x86_64 x86_64 GNU/Linux
Run Code Online (Sandbox Code Playgroud)

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

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

  2. 所有 libstdc++ 目标的答案都相同吗?

  3. 所有 libc++ 目标的答案都相同吗?

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

Mar*_*dun 5

我不确定您是否在问您想要回答的问题。我看到的一件事是您询问稳定时钟和系统时钟在精度方面的差异。第二个,仅从代码片段来看,是关于 system_clock::now、duration_cast、vector::push_back/vector::insert 和(隐式)vector::resize 的性能。

如果您不介意的话,我将尝试回答这两个问题中的第一个问题:

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

因此,询问任何特定的实现并希望它们的常量也将用于其他实现(即使对于同一供应商)是不可取的。我总是尝试使用时钟的::时间点或其::持续时间,或者作为最后的手段,使用毫秒或纳秒,具体取决于我测量的内容以及测量的物体的飞行速度。

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

修改后的代码片段使用steady_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";
        }
}
Run Code Online (Sandbox Code Playgroud)

编辑:哦,另一件事是原始代码中没有任何内容可以证明您的库使用 nano 作为 system_clock 中的周期。您正在执行uration_cast<nanoseconds>(如果必须,则使用整数除法)并从中获取周期,但是具有不同的持续时间,例如duration_cast<duration<long long, pico>>,您也可以在下面的某处获得非零值最低的 1000。不太可能,但也有可能。

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