C++11为了表示时间,新增加了chrono
库。这是一个比原本C库更加好用的时间表达库。
想要使用chrono,请包含chrono
头文件并且使用命名空间chrono
。
一个最基本的例子
首先我们来通过一个基本的例子学习chrono库的操作,现在我想要测量下面这个函数运行的时间:
|
|
首先,我们需要得到函数运行之间的时间:
|
|
steady_clock
是一个稳定时钟,最适用于测量时间,所以我们用这个时钟。它是一个静态类,直接通过其静态函数now()
(也是唯一一个函数)以获得当前的时间点。
注意now()
返回的是时间点,而不是C语言通常意义上的时间。时间点用time_point
模板类表示。
所以我们的返回值是一个steady_clock::time_point
类型,表示是steady_clock
的时间点类型(不同的时钟时间点不一样,后面会说道)。
然后我们可以如法炮制,得到函数运行后的时间:
|
|
接下来我们需要得到经过的时间,方法是将两个时间点相减:
|
|
这里需要用一下常识:时间点和时间点相减,显然代表经过的时间段。时间段使用duration
模板类表示,其模板参数为时间段秒数的数据类型。这里使用浮点型。
最后我们输出经过的时间:
|
|
通过count()
可以得到经过的秒数。
深入chrono
从上面的例子中,我们可以得知chrono时间库的基本概念:
- 时间点
time_point
:用于表示一个时间点 - 时间段
duration
:用于表示一段时间 - 时钟:时钟有三个,都是静态的
system_clock
:系统时钟,通过调用其now()
函数来得到当前系统时间steady_clock
:稳定时钟,最适用于测量时间间隔high_resolution_clock
:高精度时钟。不推荐使用,理由是不跨平台,而且通常的实现就是system_clock或者steady_clock。
接下来我们更加深入地看一看这些概念
时钟
时钟的精确定义是:
时钟由起点(或纪元)及计次频率组成。例如,时钟可以拥有 1970 年 1 月 1 日的纪元,和每一秒的计次。
简单来说,时钟首先需要一个起点,比如1970年1月1日凌晨12点整。然后由于是时钟,需要计时的嘛,还得给一个计次频率,就是隔多长时间时钟的指针动一下。我们日常生活以秒计,那么计次频率就是1秒。而有些时候你可能需要以15分钟计,或者30分钟计,那计次频率就是15分钟或30分钟。
chrono不允许我们定义时钟,我们只能用其定义的两个时钟之一(high_resolution_clock不做说明)。这些时钟都是静态类。
system_clock
定义如下:
大多数系统上,系统时间可以在任何时候被调节。它是唯一有能力映射其时间点到 C 风格时间的 C++ 时钟。
不指定
system_clock
的起始时间,但多数实现使用 Unix 时间(即从协调世界时 (UTC) 1970 年 1 月 1 日星期四 00:00:00 开始的时间,不计闰秒)。
注意,这是唯一有能力映射时间点到C风格(time_t类型)的C++时钟,这意味着steady_clock
没办法做到和C时间相互转换。
system_clock
的计次频率不同机器不一样,一般都是一纳秒或者几纳秒。
通过其now()
函数得到当前的时间点,返回值类型为system_clock::time_point
。
例子-获得当前时间点:
chrono::system_clock::time_point time = chrono::system_clock::now();
cout<<time.time_since_epoch().count()<<endl;
注意这里的第二行获得时间的方式,time_point
模板类可以通过time_since_epoch()
的方式得到从时钟起始时间到当前时间点经过的时间间隔。这里其实就是返回系统当前的时间,和C语言的time()
一样(而且比C语言还精确)。
其和C语言时间转换通过其静态函数to_time_t()
和from_time_t()
实现。
steady_clock
steady_clock
是不随着系统时钟改变的时钟,最适用于记录时间间隔的时钟。
意思就是说,在你使用steady_clock
的使用修改了系统时间,这个时钟的结果是不会受到影响的。
其只有一个静态方法now()
用于得到当前时间点。
时间点time_point
类模板
std::chrono::time_point
表示时间中的一个点。它被实现成如同存储一个Duration
类型的自Clock
的纪元起始开始的时间间隔的值。
简单来说,time_point一般内含一个duration
。
现在我们来看一下其模板声明:
|
|
可以看到,其有两个模板参数,分别是时间点对应的时钟的类型,和时钟对应的时间段类型。所以不同的时钟是拥有自己的时间点的,不同时钟之间的时间点不能相互转换。
使用time_since_epoch
可以得到时钟起始时间到当前时间点之间的时间段。
时间段duration
通过时间点之间的加减法(也没有其他运算法则),我们可以得到时间段。其模板定义如下
|
|
它由
Rep
类型的计次数和计次周期组成,其中计次周期是一个编译期有理数常量,表示从一个计次到下一个的秒数。存储于
duration
的数据仅有Rep
类型的计次数。若Rep
是浮点数,则duration
能表示小数的计次数。Period
被包含为时长类型的一部分,且只在不同时长间转换时使用。
简单来说,Rep
表示了计次数这个数据的类型,而Period
则代表计次周期。如果你的Rep
是int,那么duration只能记录一个计次周期,两个计次周期。若为float,则可以记录1.5个计次周期。
所以可以看到,不同的时钟和时间点对应的时间段也不一样。同类型的时间段存在四则运算和自增,自减运算。不同时间段之间可以使用duration_cast()
转换函数来转换。
通过count()
函数得到其记录的时间(实际是计次周期的计数)。
chrono还给出了一些常用duration的typedef:
|
|
总结
其实不需要自己定义时间点和时间段,但是深入理解他们的实现方式,有助于我们了解不同时间段和时间点之间的转换关系。