补充如何在C20中测量一个函数或者功能的运行时间
补充:如何在C++20中测量一个函数或者功能的运行时间
之前写过一篇
,最近发现了个新的
chrono
。
虽然
chrono
是 C++11 新增的,但是那时候很少使用,因为很多设计还不完善。加之当时的情况与其他方法相比并不占优。好在 C++20 进行了很多修改,优势起来了,所以现在很多代码里都使用的chrono
。本文使用的一些特性是 C++20 才有的,早期版本可能能用,但不保证。
这种方法没有之前博客里写的通用,但是代码量简单多了(真的是少了很多很多)。
但是我不好说哪个好,哪个坏。因为我不像之前那篇博客,几种方法都使用了很长时间,对优缺点非常清楚。所以这里只是记录一下
chrono
的用法,未来可能会更新。写本文是因为现在 C++ 代码中,
chrono
的出场率越来越高,至少要了解一下吧。
chrono 这个单词是天文(chronometer)的缩写,也有种说法是来自希腊语的 chrónos:希腊神话里的 chrónos 是时间之父。
看了下文档,
chrono
可以看作是
time
的后继者。主要功能是格式化打印时间(也是,其他家语言都有相关现代标准库,但是 C++ 相关的有点“老”,但这也导致使用起来非常复杂)。所以一般情况下,计时和之前那篇博客的逻辑不太一样:
chrono
计时就是获取系统时间,然后做差,而
clock_gettime
获取的是设备上的计时器/计数器来实现的。
当然你也可以在
chrono
使用计数器,后面会说。
本文主要是讲运行时间,也就是间隔时间,格式化打印系统时间这里不赘述。
系统时间计算运行时间
复杂版
先直接上代码(下面这个代码不是最简的,也不好写,这里主要是为了说明代码,后面会放个简化的代码):
#include <chrono>
std::chrono::time_point<std::chrono::system_clock> start = std::chrono::system_clock::now();
...需要被测量的代码
std::chrono::time_point<std::chrono::system_clock> end = std::chrono::system_clock::now();
std::chrono::duration<double, std::nano> elapsed = end - start;
// 注意,这里是elapsed.count(),而不是简单使用elapsed
std::cout<<elapsed.count()<<endl;
现在来讲一下这个代码的含义。
可以看到获取开始、结束时间的时候,使用的是
system_clock
,也就是系统时间。如果你想使用计数器,那么改成
steady_clock
(这部分后面会举个例子,现在还不能说)。
继续往后看,可以注意到,计算差值的时候,前面的类型是
std::chrono::duration<double, std::nano>
,其他部分都很好理解,但是这里的
<double, std::nano>
,前者是双精度浮点类型,后者是啥意思呢?
这就是不太一样的地方,这里
nano
表示计时单位是纳秒。还记得
clock_gettime
的时候吗,我们为了转换时间单位需要进行大量计算(反正我每次用都是复制的,谁每次都手写啊)。这里的
nano
是
std
里设置的一些量(这是个比率),可以换成其他的单位,如下(可以看到不光有时间的单位):
需要注意这里是个比率,如果把
nano
改成
deci
(十进制的意思),比率也就是
deci
,最后获得的秒数就是 10 倍的实际秒数。打印的时候记得除以 10。
当然我这里是举个例子,实际用的时候你可以直接用
nano
,然后除以1e9
,也一样的。
简化版
都 C++20 了,很多事情都可以简化了。根据 C++ 基金会调查统计,2024 年只有 30% 的人使用 C++20,很多事情也不一样了:
所以这里你可以偷懒,把上面的数据类型改成
auto
,都 C++20 了,就别老扣数据类型了:
#include <chrono>
// 使用std::literals之后,你就可以直接使用`1s`来表示1秒,太方便了
using namespace std::literals;
auto start = std::chrono::system_clock::now();
...需要被测量的代码
auto end = std::chrono::system_clock::now();
std::cout<< "ms: " << (end - start)/ 1ms << std::endl;
std::cout<< "s: " << (end - start)/ 1s << std::endl;
运行之后是这样的:
$ ./a.out
ms: 2317
s: 2
这代码量是不是相当少,还少了计算时间的时候处理数据类型转换的步骤。
计数器计算运行时间
现在回到前面
steady_clock
到部分,如果用计数器来计算时间呢?
就是把
system_clock
改成
steady_clock
。这里我们直接用简化版:
#include <chrono>
auto start = std::chrono::steady_clock::now();
...需要被测量的代码
auto end = std::chrono::steady_clock::now();
时间的使用方法和系统时间一模一样。