目录

补充如何在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 的时候吗,我们为了转换时间单位需要进行大量计算(反正我每次用都是复制的,谁每次都手写啊)。这里的 nanostd 里设置的一些量(这是个比率),可以换成其他的单位,如下(可以看到不光有时间的单位):

https://i-blog.csdnimg.cn/direct/c454064c715545a3ba7dbdfb1237764b.png

需要注意这里是个比率,如果把 nano 改成 deci (十进制的意思),比率也就是 deci ,最后获得的秒数就是 10 倍的实际秒数。打印的时候记得除以 10。

当然我这里是举个例子,实际用的时候你可以直接用 nano ,然后除以 1e9 ,也一样的。

简化版

都 C++20 了,很多事情都可以简化了。根据 C++ 基金会调查统计,2024 年只有 30% 的人使用 C++20,很多事情也不一样了:

https://i-blog.csdnimg.cn/direct/51ba7ac90e6f485e817c1facbbb30495.png

所以这里你可以偷懒,把上面的数据类型改成 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();

时间的使用方法和系统时间一模一样。

参考资料