有个很奇怪的现象,我自认为写得好的文章阅读量只有一百多,随手写的却有一千多——要么是胡搞,要么是比较浅显。纵观博客园里众多阅读过万的文章,若非绝世之作,则必为介绍入门级知识的短文。为了让我的十八线博客上升到十七线,我打算写几篇短文。当然,短不等于随便,不等于不负责任。客观的,要有确凿的依据,代码必须调通;主观的,观点尽量全面。

前两天写C++值多态,最后有一个性能比较,需要测量程序运行的时间,于是我重温了相关知识,现整理如下。

C风格

在C程序和C++11以前的C++程序中,测量程序运行时间一般使用clock函数和CLOCKS_PER_SEC常量,定义在<time.h>中。

clock_t是一种能表示时钟周期数的算术类型,在MSVC和GCC中都是long

clock函数返回自一个与程序执行相关的时间起至调用时刻经过的时钟周期数,类型为clock_t。由于起始时间是由实现定义的,clock函数的返回值没有直接的意义,只有两次调用clock的结果之差才有意义。

CLOCKS_PER_SEC表示一秒有多少个时钟周期,在MSVC和GCC中都是1000,即C风格时间测量的精度为1毫秒。如果long的大小是4字节,clock溢出需要24天,一般情况下足够使用。

#include <stdio.h>
#include <time.h> int work()
{
int sum = 0;
for (int i = 0; i < 1e8; ++i)
sum += i * i;
return sum;
} int main()
{
clock_t start, finish;
start = clock();
volatile int result = work();
finish = clock();
printf("%fms\n", (double)(finish - start) / CLOCKS_PER_SEC * 1000);
}

C++风格

从C++11起,C++提供了更加现代的时间工具,定义在<chrono>中,namespace std::chrono下。

chrono库主要定义了三种类型:时钟(clock)、时间点(time point)和时间段(duration)。时钟产生时间点,时间点相减得到时间段,时间点加减时间段得到时间点。由于有auto自动类型推导和运算符重载的存在,我们在使用时很少需要写明与时间相关的变量的类型。

C++标准规定了3种时钟:

  • system_clock,系统范围的挂钟,可以理解为桌面右下角的时钟,这个时钟是可以调节的,因此system_clock的返回值可能不是单调的;

  • steady_clock,稳定的、单调的时钟,不受系统时间调节的影响,因而适合于测量时间间隔,通常测量程序运行时间就用steady_clock

  • high_resolution_clock,可用的最高精度的时钟,可以是上面两个的别名。

每个时钟都有静态方法now返回当前的时间点,is_steady常量表示时钟是否单调(steady_clock::is_steady一定为true)。system_clock是唯一能与C中time_t互通的时钟。

时钟定义了成员类型period,表示一个时钟周期的时长(以秒为单位)。在MSVC和GCC中,steady_clock::period都是nano,理论上的分辨率为纳秒。

两个时间点相减可以得到时间段,调用其count函数可以获得其数值,这个时间段的类型是由实现定义的。标准还定义了millisecondsseconds等类型,为了得到以我们想要的单位表示的时间段,可以用duration_cast来转换:

#include <iostream>
#include <chrono> int work()
{
int sum = 0;
for (int i = 0; i < 1e8; ++i)
sum += i * i;
return sum;
} int main()
{
auto start = std::chrono::steady_clock::now();
volatile int result = work();
auto finish = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(finish - start);
std::cout << duration.count() << "ms" << std::endl;
}

但是这样只能输出整数毫秒,如果想要更精确一点,一种方法是转换成microseconds以后除以1000.0,更优雅地可以自己定义一种时间段类型,如duration<double, milli>,其中double表示这种时间段类型用double来存储时钟周期数量,milli表示时钟周期为1ms。从由整数表示的duration到由浮点数表示的duration的转换可以由duration的构造函数来完成,无需再用duration_cast

auto start = std::chrono::steady_clock::now();
volatile int result = work();
auto finish = std::chrono::steady_clock::now();
using milliseconds = std::chrono::duration<double, std::milli>;
milliseconds duration = finish - start;
std::cout << duration.count() << "ms" << std::endl;

睡眠

另一个与时间相关的常用功能是程序睡眠,在C++11以前没有标准的函数可以实现,C++11引入的并发解决了这个需求。

std::this_thread::sleep_for用于使当前线程挂起一段时间,其参数类型为duration模板实例,可以用milliseconds(100)等创建,也可以在using namespace std::chrono_literals后直接写100ms(需要C++14)。参数不是普通整数,也就没有了时间单位上的歧义。

#include <chrono>
#include <thread> using namespace std::chrono_literals; int main()
{
std::this_thread::sleep_for(100ms);
}

测量C++程序运行时间的更多相关文章

  1. C#测量程序运行时间及cpu使用时间

    转载:http://www.cnblogs.com/yanpeng/archive/2008/10/15/1943369.html 对一个服务器程序想统计每秒可以处理多少数据包,要如何做?答案是用处理 ...

  2. C#测量程序运行时间及cpu使用时间实例方法

    private void ShowRunTime() { TimeSpan ts1 = Process.GetCurrentProcess().TotalProcessorTime; Stopwatc ...

  3. 检测Java程序运行时间的2种方法(高精度的时间[纳秒]与低精度的时间[毫秒])

    第一种是以毫秒为单位计算的. 代码如下: long startTime=System.currentTimeMillis(); //获取开始时间 doSomeThing(); //测试的代码段 lon ...

  4. PAT乙级 1026. 程序运行时间(15)

    1026. 程序运行时间(15) 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 要获得一个C语言程序的运行时间, ...

  5. VC中监测程序运行时间(二)-毫秒级

    /* * 微秒级计时器,用来统计程序运行时间 * http://blog.csdn.net/hoya5121/article/details/3778487#comments * //整理 [10/1 ...

  6. PAT-乙级-1026. 程序运行时间(15)

    1026. 程序运行时间(15) 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 要获得一个C语言程序的运行时间, ...

  7. java中读取程序运行时间

    第一种是以毫秒为单位计算的. Java代码 //伪代码 long startTime=System.currentTimeMillis();   //获取开始时间 doSomeThing();  // ...

  8. Java计算两个程序运行时间

    一.获取系统当前时间 long startTime = System.currentTimeMillis(); //获取开始时间 doSomething(); //测试的代码段 long endTim ...

  9. 三种计算c#程序运行时间的方法

    三种计算c#程序运行时间的方法 第一种: 利用 System.DateTime.Now // example1: System.DateTime.Now method DateTime dt1 = S ...

随机推荐

  1. Natas6 Writeup(PHP Include)

    Natas6: 该题提供了php源码,点击查看分析,发现调用了includes/secret.inc页面,在输入一个变量secret后,如果和includes/secret.inc中 预设的secre ...

  2. Fiddler1 简单使用

    1.Fiddler下载地址:https://www.telerik.com/download/fiddler 2.Fiddler设置: Fiddler是强大的抓包工具,它的原理是以web代理服务器的形 ...

  3. Python专题——详解enumerate和zip

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第7篇文章,我们继续介绍迭代相关. enumerate 首先介绍的是enumerate函数. 在我们日常编程的过程当 ...

  4. 【简说Python WEB】Web应用部署

    目录 [简说Python WEB]Web应用部署 应用层 缓存层 数据层 Gunicorn 的应用 1.安装Gunicorn 2.Gunicorn的启动 Nginx 的应用 1.docker方式部署安 ...

  5. PHP之从反向删除单链表元素的问题谈起

    在完成一个单链表的删除指定元素的题目中,我发现了一件神奇的事情,php对象赋值给另外一个变量后,可以如同引用传值一般继续利用新的变量来实现链表的链接. 后面经过查证后发现: PHP7.0版本除了对象, ...

  6. 终极解决方案——sbt配置阿里镜像源,解决sbt下载慢,dump project structure from sbt耗时问题

    #sbt下载慢的问题 默认情况下,sbt使用mvn2仓库下载依赖,如下载scalatest时,idea的sbtshell 显示如下url https://repo1.maven.org/maven2/ ...

  7. 【SQL SERVER重新认识】数据内部存储结构简单探索

    数据库经常需要打交道,但是从来没想过数据库内部是如何存储数据. 今天探索一下数据库内部如何存储数据,从下面几个方面探索 数据库内部如何存储数据 索引数据如何存储 操作数据对存储影响 总结 数据库内部如 ...

  8. OpenCV-Python 如何使用背景分离方法 | 四十六

    目标 背景分离(BS)是一种通过使用静态相机来生成前景掩码(即包含属于场景中的移动对象像素的二进制图像)的常用技术. 顾名思义,BS计算前景掩码,在当前帧与背景模型之间执行减法运算,其中包含场景的静态 ...

  9. 面试刷题26:新冠攻击人类?什么攻击java平台?

    可恶的新冠病毒攻击人类,搞得IT就业形势相当不好?好在有钟南山院士带领我们提前开展好了防护工作! java作为基础平台安装在各种移动设备,PC,小型机,分布式服务器集群,各种不同的操作系统上.所以,对 ...

  10. coding++:Spring Boot全局事务解释及使用(一)

    Spring 事务的入口: TxAdviceBeanDefinitionParser 解释 <tx:advice/> 这里将解析tx的配置. @Override protected Cla ...