《深入应用C++11》笔记-时间相关工具chrono,duration、time_point、clock

本文介绍了C++11中的时间处理功能,包括chrono库的基本使用方法,如duration表示时间段,time_point表示时间点,以及system_clock、steady_clock和high_resolution_clock等时钟的特性与用途。

上一篇:《深入应用C++11》笔记-异步线程操作std::async、std::future、std::promise、std::packaged_task

chrono是一个模版库,包含了一系列时间相关功能。

duration

std::chrono::duration 和字面意思一样,表示一段时间,原型是一个模板类:

template<
    class Rep, 
    class Period = std::ratio<1> 
> class duration;

Rep表示一种数值类型,用来表示Period的数量,比如int、float。
Period是ratio类型,代表用秒表示的时间单位,默认为std::ratio<1> ,std::ratio代表一个分数,如下代码,N是分子,D是分母。

template <intmax_t N, intmax_t D = 1> struct ratio;

Period是std::ratio<1>时,说明分数为1/1,也就是1秒。

在chrono中预定义了一系列的duration:

typedef duration<long long, nano> nanoseconds;
typedef duration<long long, micro> microseconds;
typedef duration<long long, milli> milliseconds;
typedef duration<long long> seconds;
typedef duration<int, ratio<60> > minutes;
typedef duration<int, ratio<3600> > hours;

以seconds为例,Period为std::ratio<1>代表1s,std::chrono::seconds(10)就代表10秒。
以minutes为例,Period为std::ratio<60>代表60s,std::chrono::minutes(10)就代表10分钟。
以milliseconds为例,Period为milli(typedef ratio<1, 1000>)代表1/1000s,std::chrono::minutes(10)就代表10毫秒。

duration对象常用于std::this_thread::sleep_for、std::timed_mutex::try_lock_for等函数,作为入参:

std::this_thread::sleep_for(std::chrono::seconds(10));  // 等待10s

另外,C++11还提供了duration之间的类型转换duration_cast,用于不同时间精度间的装换:

#include <iostream>
#include <chrono>

int main()
{
    std::chrono::seconds scd(10);
    std::cout << scd.count() << std::endl;   // 10
    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(scd).count() << std::endl;     // 10000

    return 0;
}

// 精度高转换成精度低的时候会导致精度丢失,需要注意
#include <iostream>
#include <chrono>

int main()
{
    std::chrono::milliseconds scd(10001);
    std::cout << scd.count() << std::endl;      // 10001
    std::cout << std::chrono::duration_cast<std::chrono::seconds>(scd).count() << std::endl;                     // 10

    return 0;
}

time_point

std::chrono::time_point用于表示一个时间点,需要为时间点指定参考时钟(clock,clock类需要满足指定要求,详见https://zh.cppreference.com/w/cpp/named_req/Clock)和相对于参考时钟步进值。它被实现成如同存储一个 Duration 类型的自 Clock 的纪元起始开始的时间间隔的值。

template 
<class Clock, class Duration = typename Clock::duration>
class time_point;

例如以下代码,其中system_clock::time_point被定义为time_point,system_clock是C++11实现的clock类(一般是从格林威治标准时间开始),此处作为time_point模板的第一个类型,第二个类型Clock::duration被定义为microseconds,也就是说time_point表示从格林威治标准时间(1970-01-01 00:00:00.000)开始到指定时间的毫秒数。

#include <iostream>
#include <chrono>
using namespace std::chrono;

int main()
{
    system_clock::time_point now = system_clock::now();  // now表示当前时间到格林威治标准时间的毫秒数
    //等效于time_point<system_clock> now = system_clock::now();

    std::cout << now.time_since_epoch().count() << std::endl;  // 1534602834436896
    return 0;
}

time_point对象常用于std::this_thread::sleep_until、std::timed_mutex::try_lock_until等函数,作为入参:

#include <iostream>
#include <chrono>
#include <thread>
using namespace std::chrono;

int main()
{
    system_clock::time_point until = system_clock::now();
    until += seconds(5);
    std::this_thread::sleep_until(until);   // 一直等待到当前时间加上5s之后的时间点

    return 0;
}

同样,time_point也支持精度装换time_point_cast:

#include <iostream>
#include <chrono>
using namespace std::chrono;

int main()
{
    time_point<system_clock> now = system_clock::now();
    std::cout << now.time_since_epoch().count() << std::endl;  // 毫秒级

    time_point<system_clock, hours> hour_now =
        time_point_cast<hours>(system_clock::now());
    std::cout << hour_now.time_since_epoch().count() << std::endl;   // 小时级

    return 0;
}

clock

C++11新增了时钟的概念,时钟 (Clock) 概念描述由 std::chrono::duration 、 std::chrono::time_point 和获取当前 time_point 的函数 now() 组成的一束内容,将时钟的 time_point 原点定为时钟的纪元。C++11中有三种时钟:system_clock,steady_clock和high_resolution_clock。

system_clock表示本地系统的时钟,因此是不稳定的,因为有可能被修改,上文已经举例了一些它的用法,下面再列举一个常用的显示当前系统时间的用法:

#include <iostream>
#include <chrono>
#include <ctime>
#include <iomanip>
using namespace std::chrono;

int main()
{
    time_point<system_clock> now = system_clock::now();
    time_t t_now = system_clock::to_time_t(now);
    tm* tm_now = std::localtime(&t_now);
    std::cout << std::put_time(tm_now, "%Y-%m-%d %H:%M:%S") << std::endl;

    return 0;
}

steady_clock表示稳定的时间间隔,后一次调用now()得到的时间总是比前一次的值大(如果中途修改了系统时间,也不影响now()的结果),所以通常用来计算时间间隔:

#include <iostream>
#include <chrono>
#include <thread>
using namespace std::chrono;

int main()
{
    time_point<steady_clock> begin_time = steady_clock::now();
    std::this_thread::sleep_for(milliseconds(10));
    time_point<steady_clock> end_time = steady_clock::now();

    // steady_clock的精度为纳秒,装换成毫秒输出
    std::cout << duration_cast<milliseconds>(end_time - begin_time).count() << std::endl;

    getchar();
    return 0;
}

high_resolution_clock 表示实现提供的拥有最小计次周期的时钟,它可以是system_clock或steady_clock的别名,或第三个独立时钟。在我的实验的机器中被定义为:

typedef steady_clock high_resolution_clock;
`std::chrono::steady_clock::time_point` 是 C++ 标准库 `<chrono>` 中的一个类型,用于表示时间点(time point),它基于 `std::chrono::steady_clock` 时钟。这个时钟是单调递增的,不会受到系统时间调整的影响,因此非常适合用于测量时间间隔(如性能测试、计时等)。 下面是一个使用 `std::chrono::steady_clock::time_point` 测量代码执行时间的例子: ```cpp #include <iostream> #include <chrono> // 包含 chrono 头文件 #include <thread> // 用于 std::this_thread::sleep_for int main() { // 获取当前时间点 auto start = std::chrono::steady_clock::now(); // 模拟一些耗时操作 std::this_thread::sleep_for(std::chrono::seconds(2)); // 再次获取时间点 auto end = std::chrono::steady_clock::now(); // 计算时间间隔,单位为秒 std::chrono::duration<double> elapsed_seconds = end - start; // 输出耗时 std::cout << "Elapsed time: " << elapsed_seconds.count() << " seconds" << std::endl; return 0; } ``` ### 解释: 1. `std::chrono::steady_clock::now()` 返回当前的时间点(`time_point` 类型)。 2. `std::chrono::duration<double>` 表示两个时间点之间的持续时间,以秒为单位(`double` 类型可以表示小数秒)。 3. `elapsed_seconds.count()` 返回时间间隔的具体数值。 在这个例子中,我们使用 `std::this_thread::sleep_for` 来模拟一个耗时的操作(休眠2秒),然后通过 `start` 和 `end` 时间点之间的差值来计算这段操作的耗时。 ### 相关问题:
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值