[C++基础] 函数技巧 - 计时函数
Posted WangBo_NLPR
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[C++基础] 函数技巧 - 计时函数相关的知识,希望对你有一定的参考价值。
前言
[C++基础] 系列是以我在工作中的系统研发笔记为基础加以整理推出的。该系列内容主要涉及C/C++中的基础知识,常用函数的使用说明和技巧,讨论函数在不同平台(windows和linux)、不同编译器版本环境下的差异,指出函数使用过程中的大坑,并给出笔者在研发中常用的代码示例。
本文内容主要整理自笔者的工作笔记中:关于C++时间统计部分的资料和心得。仔细对比了C++中不同时间函数的使用方式,计时准确性,多线程安全性等,并给出了常用的代码示例。
文章小节安排如下:
1)综述
2)clock() / clock_t
3)time() / time_t
4)gettimeofday() / struct timeval
5)clock_gettime() / struct imespec
6)补充资料
一、综述
函数 | 平台 | 头文件 | 多线程 | 精度 |
---|---|---|---|---|
clock() / clock_t | Windows/Linux | #include <time.h> | 不支持 | 毫秒 |
time() / time_t | Windows/Linux | #include <time.h> | 支持(有坑) | 秒 |
gettimeofday() / struct timeval | UNIX/LINUX | #include <time.h> #include <sys/time.h> | 支持 | 微秒 |
clock_gettime() / struct imespec | UNIX/LINUX | #include <time.h> #include <sys/time.h> | 支持 | 纳秒 |
-
二、clock() / clock_t
函数 | 平台 | 头文件 | 多线程 | 精度 |
---|---|---|---|---|
clock() / clock_t | Windows/Linux | #include <time.h> | 不支持 | 毫秒 |
-
2.1 函数说明
函数 clock() 返回值类型是clock_t,是一个long类型,表示进程运行时间,单位是CPU时钟计时单元(clock tick)数,或者说滴答数(ticks)。一般用两次clock函数来计算进程自身运行的时间。
注意,
当程序单线程或者单核心机器运行时,这种时间的统计方法是正确的。当多线程并发时候clock()函数就会不准确,因为clock()将返回进程总的时钟计时单元数量,而不是当前线程的。
2.2 关于CLOCKS_PER_SEC
CLOCKS_PER_SEC 用来定义当前环境下一秒钟有多少个时钟计时单元,例如:
#define CLOCKS_PER_SEC ((clock_t)1000)
2.3 Code Sample
clock_t time_start;
clock_t time_end;
time_start= clock();
// func()
time_end= clock();
// diff-second
double time_diff_sec = ((double)(time_end- time_start) / CLOCKS_PER_SEC);
printf("lib: time diff: %fs.\\n", time_diff_sec);
-
三、time() / time_t
函数 | 平台 | 头文件 | 多线程 | 精度 |
---|---|---|---|---|
time() / time_t | Windows/Linux | #include <time.h> | 支持(有坑) | 秒 |
-
3.1 函数说明
函数 time() 返回从 UTC 1970-1-1 0:0:0 开始到现在(调用函数时刻)的秒数。
注意,
time_t方式在自定义多线程方式下没有问题,但在某些rpc框架下(比如thrift下)计时存在问题,大坑!
如果想在thrfit的线程池模式下计算线程耗时,请使用timeval或者timespec。
3.2 Code Sample
time_t time_start;
time_t time_end;
time_start = time(NULL);
// func()
time_end = time(NULL);
// diff-second
double time_diff_sec = difftime(time_end, time_start);
// print
printf("lib: start time: %s", ctime(&time_start));
printf("lib: end time: %s", ctime(&time_end));
printf("lib: time diff: %fs.\\n", time_diff_sec);
-
四、gettimeofday() / struct timeval
函数 | 平台 | 头文件 | 多线程 | 精度 |
---|---|---|---|---|
gettimeofday() / struct timeval | UNIX/LINUX | #include <time.h> #include <sys/time.h> | 支持 | 微秒 |
-
4.1 函数说明
函数 gettimeofday() 返回的timeval值为Epoch(00:00:00 1970-01-01 UTC)到创建struct timeval 时的时间,tv_sec 为秒数部分,tv_usec 为微秒数部分(10的-6次方秒)。
结构体 struct timeval 在time.h中的定义为:
struct timeval
time_t tv_sec; /* Seconds. */
suseconds_t tv_usec; /* Microseconds. */
;
4.2 Code Sample
struct timeval t1, t2;
gettimeofday(&t1, NULL);
// func()
gettimeofday(&t2, NULL);
// diff-second
double time_diff_sec = (t2.tv_sec-t1.tv_sec) + (t2.tv_usec-t1.tv_usec)/1000000;
-
五、clock_gettime() / struct imespec
函数 | 平台 | 头文件 | 多线程 | 精度 |
---|---|---|---|---|
clock_gettime() / struct imespec | UNIX/LINUX | #include <time.h> #include <sys/time.h> | 支持 | 纳秒 |
-
5.1 函数说明
函数 clock_gettime() 返回的imespec值为特定时刻到创建struct timeval 时的时间,tv_sec 为秒数部分,tv_usec 为微秒数部分(10的-9次方秒)。
结构体 struct imespec在time.h中的定义为:
struct timespec
time_t tv_sec; /* Seconds. */
long tv_nsec; /* Nanoseconds. */
;
常用的4时刻如下:
CLOCK_REALTIME 系统当前时间(从UTC1970-1-1 0:0:0算起)
CLOCK_MONOTONIC 系统的启动时间
CLOCK_PROCESS_CPUTIME_ID 本进程运行时间
CLOCK_THREAD_CPUTIME_ID 本线程运行时间
clock_gettime() 和 gettimeofday() 函数精度更高并且是线程安全的,因此在多线程中计时采用该函数是比较好的选择。
5.2 Code Sample
struct timespec t1, t2;
clock_gettime(CLOCK_MONOTONIC, &t1);
// func()
clock_gettime(CLOCK_MONOTONIC, &t2);
// diff-second
double time_diff_sec = (t2.tv_sec-t1.tv_sec) + (t2.tv_usec-t1.tv_usec)/1000000;
-
六、补充资料
6.1 关于Epoch
Epoch指的是一个特定的时间:1970-01-01 00:00:00 UTC。
定义如下:
A timepoint is defined as combination of a duration and a beginning of time (the so-called epoch). A typical example is a timepoint that represents “New Year’s Midnight 2000,” which is described as “1,262,300,400 seconds since January 1, 1970” (this day is the epoch of the system clock of UNIX and POSIX systems).
6.2 Unix时间戳
Unix时间戳(Unix timestamp),或称Unix时间(Unix time)、POSIX时间(POSIX time)。Unix时间戳是一种时间表示方式,定义为是从Epoch(1970年1月1日00:00:00 UTC)开始到现在所经过的秒数。
6.3 关于UTC time
协调世界时,又称世界标准时间或世界协调时间,简称UTC(英文“Coordinated Universal Time”/法文“Temps Universel Coordonné”),是最主要的世界时间标准,其以原子时秒长为基础,在时刻上尽量接近于格林尼治标准时间。中华民国采用CNS 7648的《资料元及交换格式–资讯交换–日期及时间的表示法》(与ISO 8601类似)称之为世界协调时间。中华人民共和国采用ISO 8601:2000的国家标准GB/T 7408-2005《数据元和交换格式 信息交换 日期和时间表示法》中亦称之为协调世界时。
这套时间系统被应用于许多互联网和万维网的标准中,例如,网络时间协议(NTP, Network Time Protocol)就是协调世界时在互联网中使用的一种方式。
UTC目前来说也就是指 GMT 时间。为什么说目前就是指 GMT 时间呢?因为本初子午线(子午线即经线,本初子午线即 0 度经线)其实穿过的是沙特阿拉伯西边的麦加,而不是英国的格林威治。当时英国皇家学会暂时确定格林威治为本初子午线的穿过点,加之英国正是兴旺发达时期,全世界就将错就错,用到现在。说不定哪天改为麦加时间为标准时间也不是没有可能,所以我们一般使用 UTC,而不是 GMT。
6.4 关于GMT
格林尼治标准时间(中国大陆翻译:格林尼治平均时间或格林尼治标准时间,台、港、澳翻译:格林威治标准时间;英语:Greenwich Mean Time,GMT)是指位于英国伦敦郊区的皇家格林尼治天文台当地的标准时间,因为本初子午线被定义为通过那里的经线。
自1924年2月5日开始,格林尼治天文台负责每隔一小时向全世界发放调时信息。
理论上来说,格林尼治标准时间的正午是指当太阳横穿格林尼治子午线时(也就是在格林尼治上空最高点时)的时间。但由于地球在它的椭圆轨道里的运动速度不均匀,这个时刻可能与实际的太阳时有误差,最大误差达16分钟。原因在于地球每天的自转是有些不规则的,而且正在缓慢减速,因此格林尼治时间基于天文观测本身的缺陷,已经不再被作为标准时间使用。
UTC是根据原子钟来计算时间,现在世界上最精确的原子钟50亿年才会误差1秒(最精确原子钟问世:50亿年误差一秒),可以说非常精确。因此现在的标准时间采用由原子钟报时的协调世界时(UTC)来决定。
参考
维基百科
The C++ Resources Network
说明:
平时做笔记会参考很多网上的资料,但很多时候并没有一一记录出处,所以这里只给出了我在撰写本博客时候主要参考的资料。如果本文应用了您的文章资料还请见谅,请及时联系我进行参考资料的修改,谢谢!
以上是关于[C++基础] 函数技巧 - 计时函数的主要内容,如果未能解决你的问题,请参考以下文章