乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • C++ 学习路径
  • 第1章 C++概述与开发环境

    • C++ 语言概述与编译模型
    • 第一个 C++ 程序与规范
    • 开发环境配置
    • 预处理指令详解
  • 第2章 基本语法与类型系统

    • 变量与基本类型
    • 类型转换
    • 枚举类型
    • 引用与指针
    • 数组与 stdarray
    • 字符串与原始字符串字面量
    • const 与 constexpr
    • nullptr 与空指针
    • 类型推导 auto 与 decltype
    • 基于范围的 for 循环
    • 值类别全面解析
    • char16_t 与 char32_t
    • static_assert 编译期断言
  • 第3章 函数与重载

    • 函数声明与定义
    • 函数重载
    • 默认参数与内联函数
    • Lambda 表达式
    • 函数对象与 stdfunction
    • 后置返回类型与 noexcept
  • 第4章 类与对象

    • 类的基本定义
    • 构造函数与析构函数
    • 拷贝控制
    • 移动构造函数与移动赋值
    • 列表初始化与类内初始化器
    • 静态成员与嵌套类
    • 友元
    • =default 与 =delete
  • 第5章 继承与多态

    • 继承基础
    • 虚函数与多态
    • 虚函数表与动态绑定原理
    • 虚析构函数
    • 抽象类与纯虚函数
    • 多重继承与虚继承
    • 继承构造函数
  • 第6章 运算符重载

    • 运算符重载基础
    • 算术与关系运算符重载
    • 赋值与移动运算符重载
    • 特殊运算符重载
  • 第7章 模板与泛型编程

    • 函数模板
    • 类模板
    • 模板特化与偏特化
    • 可变参数模板
    • 别名模板与模板模板参数
    • SFINAE 与类型萃取
    • 依赖名与 typename/template 关键字
  • 第8章 异常处理

    • 异常处理机制
    • noexcept 与异常安全
    • RAII 与异常安全实践
  • 第9章 内存管理与智能指针

    • 动态内存与内存分区
    • RAII 惯用法
    • unique_ptr
    • shared_ptr 与 weak_ptr
    • 内存管理最佳实践
  • 第10章 右值引用与移动语义

    • 右值引用与值类别深度解析
    • std::move 原理与使用
    • 完美转发与 std::forward
    • 移动语义性能对比与最佳实践
  • 第11章 STL容器

    • vector 深度剖析
    • deque 内部机制
    • list 与 forward_list
    • map 与 set 深度解析
    • unordered 容器与哈希原理
    • array 与 tuple
    • 容器适配器
    • 容器选择全景指南
  • 第12章 STL算法与迭代器

    • 迭代器体系全解
    • 非变异算法
    • 变异算法
    • 排序与二分算法
    • Lambda 与算法组合
    • std::random 随机数库
    • 自定义迭代器开发
  • 第13章 IO流与文件

    • 标准 IO 流
    • 格式化输出控制
    • 文件流操作
    • 字符串流
    • std::regex 正则表达式
  • 第14章 并发与多线程

    • thread 基础与线程管理
    • mutex 与 lock_guard
    • unique_lock 与 condition_variable
    • thread_local 线程局部存储
    • atomic 与内存序
    • future 与 async 异步编程
    • std::chrono 时间库
  • 第15章 现代C++新特性

    • 从 C++11 到 C++20 演进路线
    • C++14 关键新特性
    • C++17 关键新特性
    • C++20 核心特性速览
  • 第16章 面试考点与最佳实践

    • C++ 综合最佳实践清单
    • 高频面试题精讲
    • 多线程面试题与实战
    • 内存管理常见陷阱与排查
  • 附录

    • C++ 核心知识点
    • C++ 专业术语

std::chrono 时间库

定义与作用

<chrono> 是 C++11 引入的高精度时间库,通过三大核心组件——时长(duration)、时间点(time_point)、时钟(clock)——提供类型安全、单位明确的时间处理能力,全面替代 C 风格的 time() / clock() / gettimeofday()。

#include <chrono>

auto start = std::chrono::steady_clock::now();
// ... 执行任务 ...
auto end = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "耗时: " << elapsed.count() << " ms" << std::endl;
对比C 风格<chrono>
类型安全time_t 是整数,易混用duration 带单位,编译期检查
精度秒级(time())纳秒级可配
单调性time() 受系统时间调整影响steady_clock 保证单调递增
运算手动单位换算duration_cast 自动换算

核心原理

三大组件关系

duration 的编译期单位体系

三种时钟对比

时钟特点适用场景
std::chrono::system_clock系统时钟,可转为 time_t 和日历时间需要显示日期时间
std::chrono::steady_clock单调时钟,不受系统时间调整影响性能测量、超时控制
std::chrono::high_resolution_clock最高精度(通常是 steady 或 system 的别名)对精度要求极高的测量

完整示例

示例一:飞翔科技服务性能测量

场景说明:李眉压测公司内部 API,使用 chrono 精确测量各接口延迟。

#include <iostream>
#include <chrono>
#include <thread>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>

// 模拟飞翔科技后端 API 处理
int processQuery(const std::string& apiName, int complexity) {
    // 模拟不同复杂度的处理耗时
    auto delay = std::chrono::milliseconds(10 + complexity * 5);
    std::this_thread::sleep_for(delay);
    return complexity * 42;
}

// 计时包装器:测量函数执行时间
template <typename F, typename... Args>
auto measureTime(const std::string& label, F&& func, Args&&... args) {
    auto start = std::chrono::steady_clock::now();

    auto result = std::forward<F>(func)(std::forward<Args>(args)...);

    auto end = std::chrono::steady_clock::now();

    auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);

    std::cout << "  " << std::setw(20) << std::left << label
              << std::setw(8)  << std::right << elapsed.count()
              << " μs";

    // 当耗时 > 100ms 时自动转为 ms 显示
    if (elapsed > std::chrono::milliseconds(100)) {
        auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed);
        std::cout << " (" << ms.count() << " ms)";
    }
    std::cout << std::endl;

    return result;
}

int main() {
    std::cout << "===== 飞翔科技 API 性能测试 =====" << std::endl;
    std::cout << "steady_clock 精度: 1/"
              << std::chrono::steady_clock::period::den
              << " 秒"
              << std::endl << std::endl;

    // 测试多个 API
    auto r1 = measureTime("用户登录",
                          processQuery, "/api/login", 5);
    auto r2 = measureTime("订单查询",
                          processQuery, "/api/orders", 20);
    auto r3 = measureTime("报表生成",
                          processQuery, "/api/report", 50);

    // ---- duration 算术运算 ----
    std::cout << "\n[duration 运算]" << std::endl;

    using namespace std::chrono_literals;  // C++14 字面量

    auto task1 = 150ms;    // 任务1预计用时
    auto task2 = 300ms;    // 任务2预计用时
    auto total = task1 + task2;

    std::cout << "task1 + task2 = "
              << std::chrono::duration_cast<std::chrono::milliseconds>(total).count()
              << " ms" << std::endl;

    // 比较
    if (task1 < task2) {
        std::cout << "task1 比 task2 快" << std::endl;
    }

    return 0;
}

预期输出:

===== 飞翔科技 API 性能测试 =====
steady_clock 精度: 1/1000000000 秒

  用户登录                       35000 μs
  订单查询                      110000 μs (110 ms)
  报表生成                      260000 μs (260 ms)

[duration 运算]
task1 + task2 = 450 ms
task1 比 task2 快

逐段分析:

  • steady_clock::now() 返回当前时间点——单调时钟不受用户修改系统时间的影响
  • duration_cast<microseconds>(end - start) 将时间点差值转换为微秒精度
  • std::chrono_literals(C++14)提供 150ms、3s、5min 等字面量语法
  • duration_cast 是截断转换:duration_cast<milliseconds>(1500μs) = 1ms(小数部分丢失)
  • steady_clock::period::den 获取时钟的精度分母

示例二:超时控制与时间点比较

场景说明:白歌为飞翔科技消息队列设计带超时的 consumer。

#include <iostream>
#include <chrono>
#include <thread>
#include <atomic>
#include <mutex>
#include <condition_variable>

class TimeoutConsumer {
public:
    using Clock = std::chrono::steady_clock;
    using TimePoint = Clock::time_point;

    // 等待消息,超时时间由 duration 指定
    template <typename Rep, typename Period>
    bool waitForMessage(const std::chrono::duration<Rep, Period>& timeout) {
        auto deadline = Clock::now() + timeout;

        while (Clock::now() < deadline) {
            // 模拟检查是否有消息
            std::this_thread::sleep_for(std::chrono::milliseconds(100));

            if (hasNewMessage()) {
                std::cout << "  收到消息: " << fetchMessage() << std::endl;
                return true;
            }
        }

        std::cout << "  超时!等待了 "
                  << std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count()
                  << " ms 仍无消息" << std::endl;
        return false;
    }

    void produce(const std::string& msg) {
        std::this_thread::sleep_for(std::chrono::milliseconds(300));
        lastMessage_ = msg;
        hasMessage_ = true;
    }

private:
    bool hasNewMessage() const { return hasMessage_; }
    std::string fetchMessage() {
        hasMessage_ = false;
        return lastMessage_;
    }

    std::string lastMessage_;
    bool hasMessage_ = false;
};

int main() {
    std::cout << "===== 飞翔科技消息队列超时 =====" << std::endl;

    TimeoutConsumer consumer;

    // 场景1:消息及时到达(300ms < 500ms 超时)
    std::cout << "\n[场景1 — 正常接收]" << std::endl;
    std::thread producer([&consumer]() {
        consumer.produce("孔蓝: 需求文档已更新");
    });

    bool received = consumer.waitForMessage(std::chrono::milliseconds(500));
    std::cout << "结果: " << (received ? "成功接收" : "超时") << std::endl;
    producer.join();

    // 场景2:消息未在超时前到达
    std::cout << "\n[场景2 — 超时]" << std::endl;
    received = consumer.waitForMessage(std::chrono::milliseconds(200));
    std::cout << "结果: " << (received ? "成功接收" : "超时") << std::endl;

    // ---- 时间点与 system_clock 转换 ----
    std::cout << "\n[时间点与日历时间]" << std::endl;

    auto now = std::chrono::system_clock::now();
    std::time_t now_c = std::chrono::system_clock::to_time_t(now);

    // 分解为时间结构(方便显示)
    std::tm local_tm;
    localtime_s(&local_tm, &now_c);  // Windows
    // localtime_r(&now_c, &local_tm); // POSIX

    std::cout << "当前系统时间: "
              << (local_tm.tm_year + 1900) << "-"
              << std::setfill('0')
              << std::setw(2) << (local_tm.tm_mon + 1) << "-"
              << std::setw(2) << local_tm.tm_mday << " "
              << std::setw(2) << local_tm.tm_hour << ":"
              << std::setw(2) << local_tm.tm_min << ":"
              << std::setw(2) << local_tm.tm_sec
              << std::endl;

    // 计算两个时间戳之间的天数差
    auto yesterday = now - std::chrono::hours(24);
    auto diff_hours = std::chrono::duration_cast<std::chrono::hours>(now - yesterday);
    std::cout << "距离昨天此时: " << diff_hours.count() << " 小时" << std::endl;

    return 0;
}

预期输出:

===== 飞翔科技消息队列超时 =====

[场景1 — 正常接收]
  收到消息: 孔蓝: 需求文档已更新
结果: 成功接收

[场景2 — 超时]
  超时!等待了 200 ms 仍无消息
结果: 超时

[时间点与日历时间]
当前系统时间: 2026-6-14 10:30:45
距离昨天此时: 24 小时

逐段分析:

  • 超时模式:deadline = now() + timeout,循环检查 now() < deadline
  • steady_clock 用于超时控制:单调递增,不受系统时间调整影响——避免了因 NTP 校时导致超时时间计算混乱
  • system_clock::to_time_t() 将 time_point 转为 C 风格 time_t,用于与旧 API 交互
  • time_point 之间相减得到 duration,time_point 加 duration 得到新 time_point
  • 代码使用模板接受任意 duration,调用者可自由传入 500ms、2s、1min 等不同单位

示例三:C 风格时间函数 vs chrono 对比

#include <iostream>
#include <chrono>
#include <ctime>
#include <thread>

int main() {
    std::cout << "===== C time() vs chrono =====" << std::endl;

    // ---- C 风格 ----
    std::cout << "\n[C 风格 — time_t]" << std::endl;
    std::time_t start_c = std::time(nullptr);
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    std::time_t end_c = std::time(nullptr);
    std::cout << "time() 差值: " << (end_c - start_c)
              << " 秒(精度限制在秒级)" << std::endl;

    // ---- C 风格 clock()(CPU 时间,不是挂钟时间)----
    std::cout << "\n[C 风格 — clock()]" << std::endl;
    std::clock_t start_clk = std::clock();
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    std::clock_t end_clk = std::clock();
    std::cout << "clock() 差值: " << (end_clk - start_clk)
              << " ticks(sleep 不消耗 CPU,所以几乎为 0)" << std::endl;

    // ---- chrono 风格 ----
    std::cout << "\n[chrono 风格 — steady_clock]" << std::endl;
    auto start_ch = std::chrono::steady_clock::now();
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    auto end_ch = std::chrono::steady_clock::now();

    auto elapsed_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(end_ch - start_ch);
    auto elapsed_us = std::chrono::duration_cast<std::chrono::microseconds>(end_ch - start_ch);
    auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end_ch - start_ch);

    std::cout << "chrono 测量 sleep(500ms) 实际耗时:" << std::endl;
    std::cout << "  " << elapsed_ns.count() << " ns" << std::endl;
    std::cout << "  " << elapsed_us.count() << " μs" << std::endl;
    std::cout << "  " << elapsed_ms.count() << " ms" << std::endl;

    std::cout << "\n对比总结:" << std::endl;
    std::cout << "  time():    秒级精度,测量挂钟时间" << std::endl;
    std::cout << "  clock():   毫秒级精度,测量 CPU 时间(不是挂钟)" << std::endl;
    std::cout << "  chrono:    纳秒级精度,可选单调/系统/高精度时钟" << std::endl;

    return 0;
}

预期输出:

===== C time() vs chrono =====

[C 风格 — time_t]
time() 差值: 0 秒(精度限制在秒级)

[C 风格 — clock()]
clock() 差值: 0 ticks(sleep 不消耗 CPU,所以几乎为 0)

[chrono 风格 — steady_clock]
chrono 测量 sleep(500ms) 实际耗时:
  500123456 ns
  500123 μs
  500 ms

对比总结:
  time():    秒级精度,测量挂钟时间
  clock():   毫秒级精度,测量 CPU 时间(不是挂钟)
  chrono:    纳秒级精度,可选单调/系统/高精度时钟

逐段分析:

  • time() 精度仅到秒——500ms 的 sleep 差值几乎总是 0 或 1
  • clock() 测量的是 CPU 时间而非挂钟时间——sleep 不消耗 CPU,所以差值为 0
  • chrono::steady_clock 精确到纳秒,测量的是真实的挂钟时间
  • duration_cast<不同精度级别> 在不同精度单位间转换——高精度 → 低精度时小数部分被截断

易错场景与面试考点

易错场景

场景错误表现正确做法
用 system_clock 测量性能系统时间调整导致测量不准性能测量用 steady_clock
duration_cast 精度丢失截断而非四舍五入C++17 用 round/floor/ceil
clock() 用于挂钟计时测量的是 CPU 时间,非挂钟用 steady_clock::now()
忽略 steady_clock 是否可用某些嵌入式平台不支持检查文档,必要时回退
duration 类型不匹配直接运算编译错误用 duration_cast 统一单位

常见面试问题

  1. 三种时钟的区别和选择?——system_clock 可转日历时间,受系统时间调整影响;steady_clock 单调递增,适合性能测量;high_resolution_clock 是编译器的最高精度时钟(通常是前两者之一的别名)。

  2. duration_cast 的截断行为是什么?——向零取整(truncation toward zero)。duration_cast<seconds>(1500ms) = 1s。C++17 新增 floor(向下取整)、ceil(向上取整)、round(四舍五入)。

  3. chrono 如何与 C 风格的 time_t 互操作?——system_clock::to_time_t() 将 time_point 转为 time_t,system_clock::from_time_t() 反向转换。

  4. 为什么 clock() 不能用于测量挂钟时间?——clock() 返回的是进程消耗的 CPU 时间,sleep/IO 等待期间不消耗 CPU,因此 clock() 差值接近 0。

小结

  • 三大核心:duration(带单位的时长)、time_point(时刻)、clock(时钟源)
  • 性能测量用 steady_clock(单调递增,不受系统时间调整影响)
  • 显示日历时间用 system_clock(可转为 time_t 和本地时间)
  • duration_cast 用于单位转换(截断),C++17 起可用 round/floor/ceil
  • std::chrono_literals(C++14)提供 150ms、3s 等字面量,代码更直观
  • 全面替代 C 风格的 time()(秒级)和 clock()(CPU 时间)
上一页
future 与 async 异步编程