C++ chrono

C++ chrono库的使用方法

C++ chrono

一、chrono的核心设计理念

chrono的核心是将时间抽象为三个相互关联的概念:时长(duratn)时间点(time_point)时钟(clock)。三者通过模板参数紧密耦合,形成一套自洽的类型系统:

  • 时长(duration):表示"一段时间间隔"(如10秒、500毫秒),绑定数值与单位。

  • 时间点(time_point):表示"某个具体时刻"(如2023-10-01 08:00:00),基于某个时钟的"纪元"(epoch)偏移量定义。

  • 时钟(clock):提供获取当前时间点的接口,定义了时间的参考系(如系统时间、稳定时间)。

二、核心组件详解

1. 时长(std::chrono::duration

duration是对"时间间隔"的抽象,定义为:

1
2
template <typename Rep, typename Period = std::ratio<1>>
class duration;
  • Rep:存储时长的数值类型(如intlong longdouble),决定了数值的精度和范围。

  • Period:表示时长的单位(周期),类型为std::ratio<N, D>(即N/D秒),例如:

    • std::ratio<1>:1秒(默认值)。
    • std::ratio<1, 1000>:1毫秒(1/1000秒)。
    • std::ratio<60>:1分钟(60秒)。

标准预定义时长类型
为简化常用场景,标准库定义了一系列别名(基于long long作为Rep):

1
2
3
4
5
6
using nanoseconds  = duration<long long, std::nano>;    // 1e-9秒
using microseconds = duration<long long, std::micro>; // 1e-6秒
using milliseconds = duration<long long, std::milli>; // 1e-3秒
using seconds = duration<long long>; // 1秒
using minutes = duration<long long, std::ratio<60>>; // 60秒
using hours = duration<long long, std::ratio<3600>>; // 3600秒

时长的操作

  • 算术运算:支持+-*/(如seconds(3) + milliseconds(500) = milliseconds(3500))。

  • 比较运算:支持==!=<>等(需单位兼容,或通过转换后比较)。

  • 类型转换:通过std::chrono::duration_cast显式转换(因单位不同可能丢失精度):

    1
    2
    3
    4
    5
    #include <chrono>
    using namespace std::chrono;

    milliseconds ms(1500); // 1500毫秒
    seconds s = duration_cast<seconds>(ms); // 转换为1秒(截断小数部分)

2. 时间点(std::chrono::time_point

time_point是对"具体时刻"的抽象,定义为:

1
2
template <typename Clock, typename Duration = typename Clock::duration>
class time_point;
  • Clock:关联的时钟类型(决定时间的参考系,如系统时钟、稳定时钟)。

  • Duration:表示该时间点相对于时钟"纪元"(epoch,即时钟的起始点,如Unix时间戳的1970-01-01 00:00:00)的偏移量。

时间点的操作

  • 获取纪元偏移:通过time_since_epoch()获取自纪元起的duration

    1
    2
    auto now = system_clock::now();          // 当前系统时间点
    auto epoch_offset = now.time_since_epoch(); // 自系统时钟纪元起的时长
  • 算术运算:与duration结合,生成新的时间点:

    1
    2
    auto future = now + seconds(10);  // 10秒后的时间点
    auto past = now - minutes(5); // 5分钟前的时间点
  • 比较运算:支持==!=<等(需同属一个时钟)。

3. 时钟(std::chrono::clock

时钟是time_point的"参考系",提供获取当前时间点的接口,定义了三个核心成员:

  • now():静态方法,返回当前时间点(time_point<Clock>)。

  • duration:时钟的默认时长类型(如system_clock通常使用nanoseconds)。

  • is_steady:静态常量(bool),标识时钟是否"稳定"(即时间是否单调递增,不会因系统调整而回溯)。

标准库三种时钟

  1. system_clock

    • 关联系统时间(可被用户或系统调整,如手动修改时区、NTP同步)。
    • 支持与C风格时间(std::time_t)转换,适合获取"日历时间"(如年月日时分秒)。
    • is_steadyfalse(可能因调整而回溯)。

    示例:获取当前日历时间:

    1
    2
    3
    4
    5
    6
    7
    #include <chrono>
    #include <ctime>
    using namespace std::chrono;

    auto sys_now = system_clock::now();
    std::time_t t = system_clock::to_time_t(sys_now); // 转换为time_t
    std::cout << std::ctime(&t); // 输出人类可读时间(如"Wed Jun 1 12:34:56 2023")
  2. steady_clock

    • 稳定时钟(时间单调递增,不可调整),适合测量时间间隔(如性能计时、定时器)。
    • 不关联日历时间,无法转换为time_t
    • is_steadytrue(核心优势)。

    示例:测量代码执行时间:

    1
    2
    3
    4
    5
    auto start = steady_clock::now();
    // 执行耗时操作...
    auto end = steady_clock::now();
    auto elapsed = duration_cast<milliseconds>(end - start);
    std::cout << "耗时: " << elapsed.count() << "ms\n";
  3. high_resolution_clock

    • 高精度时钟,通常是steady_clocksystem_clock的别名(取决于编译器实现)。
    • 设计目标是提供系统支持的最高精度,但需注意其is_steady可能为false(若绑定system_clock)。

三、chrono的核心优势

  1. 类型安全:时长的单位(如秒/毫秒)通过类型而非注释体现,编译器可检测单位误用(如将毫秒当作秒传入函数)。

  2. 精度可控:通过RepPeriod灵活定义时长精度(如duration<double, std::ratio<1, 10>>表示0.1秒精度的浮点数时长)。

  3. 平台无关:屏蔽了不同系统的时间实现差异(如Windows与Linux的时钟粒度不同)。

  4. 支持泛型编程:可基于durationtime_point编写通用时间处理逻辑(如模板函数支持任意时钟类型)。

四、典型应用场景

  • 性能基准测试:用steady_clock测量代码片段的执行时间。

  • 定时器实现:结合time_point管理定时任务的触发时间

  • 时间戳记录:用system_clock记录事件发生的日历时间。

  • 帧率控制:在游戏或实时系统中,用duration控制循环执行频率(如60FPS即每16.67ms执行一次)。