在C++中测量代码执行时间的两种方法
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>第一部分:C 风格clock()(“CPU 秒表”)</li><li>第二部分:现代 C++std::chrono(“高精度电子秒表”)</li><li>第三部分:新手的“头号噩梦”——clock()vs<chrono></li><li>第四部分:“X光透 视”——观察时间点</li><ul class="second_class_ul"><li>“X光”实战(基于chrono_example.cpp)</li></ul><li>动手试试!(终极挑战:你的“排序分析器”)</li><ul class="second_class_ul"></ul></ul></div><p>在C++中,编写代码只是第一步,衡量代码的“<strong>效率</strong>”同样重要。你如何知道你的 <code>sort</code> 算法比同事写的快?或者你的新功能导致了多少性能下降?你需要一个“<strong>秒表</strong>”来精确测量代码的执行时间。</p><p>在C++(及C语言)中,你有两种主要的“秒表”:</p>
<p><strong>C 风格 “CPU 秒表” (<code><ctime></code>/<code>clock()</code>)</strong>:</p>
<ul><li><strong>比喻:</strong> 这是一个老式的“机械秒表”,它只在你的 CPU **真正在为你的程序“工作”(执行指令)**时才会“嘀嗒”。</li><li><strong>特点:</strong> 它测量的是 <strong>CPU 时间 (CPU Time)</strong>。如果你的程序在“<strong>等待</strong>”(比如 <code>sleep</code>、等待用户输入或等待网络响应),这个秒表会<strong>暂停</strong>。</li><li><strong>精度:</strong> 较低,受限于 <code>CLOCKS_PER_SEC</code> 宏。</li></ul>
<p><strong>现代 C++ 风格 “高精度电子秒表” (<code><chrono></code>)</strong>:</p>
<ul><li><strong>比喻:</strong> 这是一个高精度的“电子秒表”,它测量的是<strong>墙上时钟 (Wall Clock)</strong> 走过的时间。</li><li><strong>特点:</strong> 它测量的是<strong>真实世界流逝的时间</strong>。从你按下“开始”到按下“停止”,无论你的程序是在“工作”还是“等待”,它都在计时。</li><li><strong>精度:</strong> 极高(通常可以达到纳秒 <code>ns</code> 级别)。</li><li><strong>这是现代C++中</strong>(C++11及以后)<strong>强烈推荐</strong>的方式。</li></ul>
<p><strong>在本教程中,你将学会:</strong></p>
<ul><li><strong>C 风格 <code>clock()</code></strong>:如何使用“CPU 秒表”。</li><li><strong>C++ <code>std::chrono</code></strong>:如何使用“高精度电子秒表”(<strong>推荐!</strong>)。</li><li><strong>新手的“头号噩梦”</strong>:<strong>CPU 时间</strong> vs <strong>挂钟时间</strong> (Wall Time) 的致命区别。</li><li><strong>实战演练</strong>:通过代码对比两种计时器的不同结果。</li><li><strong>“X光透 视”</strong>:用调试器“亲眼目睹”时间点(<code>time_point</code>)对象。</li></ul>
<p><strong>前置知识说明 (100% 自洽):</strong></p>
<ul><li><strong>变量 (Variable)</strong>:理解存储数据的“盒子”,如 <code>double time_taken;</code>。</li><li><strong>函数 (Function)</strong>:理解可重复使用的“代码积木”。</li><li><strong><code>#include</code></strong>:如何包含C++标准库(如 <code><iostream></code>, <code><ctime></code>, <code><chrono></code>)。</li><li><strong><code>cout</code></strong>:C++ 中用于在屏幕上打印信息的“扬声器”。</li><li><strong>类型转换 (Casting)</strong>:如 <code>double(value)</code>,将 <code>value</code> 转换为 <code>double</code> 类型。</li><li><strong>编译 (Compile)</strong>:C++代码(“食谱”)必须被“编译”(“烘焙”),才能变成电脑可执行的程序(“蛋糕”)。</li></ul>
<p class="maodian"></p><h2>第一部分:C 风格clock()(“CPU 秒表”)</h2>
<p><code>clock()</code> 函数在 <code><ctime></code> 库中。它返回程序启动到<strong>当前时刻</strong>为止,CPU 花在你程序上的“<strong>嘀嗒数</strong>”(Clock Ticks)。</p>
<p><strong>核心步骤:</strong></p>
<ol><li>包含 <code><ctime></code>。</li><li>在代码开始前,调用 <code>clock_t start = clock();</code> 记录“开始嘀嗒数”。</li><li>在代码结束后,调用 <code>clock_t end = clock();</code> 记录“结束嘀嗒数”。</li><li>计算差值 <code>double(end - start)</code>,然后除以 <code>CLOCKS_PER_SEC</code> (一个系统常量,表示“每秒多少嘀嗒数”),得到<strong>秒数</strong>。</li></ol>
<p><strong><code>clock_example.cpp</code></strong></p>
<div class="jb51code"><pre class="brush:cpp;">#include <iostream>
#include <ctime> // 1. 包含 C 时间库
using namespace std;
// 一个耗时的函数 (模拟 CPU 密集型工作)
void heavy_work() {
// 执行一个(通常会被编译器优化的)空循环来消耗 CPU 时间
// 在实际测试时,应使用 -O0 (关闭优化) 来观察
for(long i = 0; i < 3000000000L; ++i) {}
}
int main() {
cout << "--- 测试 C 风格 <ctime> (clock_t) ---" << endl;
cout << "每秒“嘀嗒”数 (CLOCKS_PER_SEC): " << CLOCKS_PER_SEC << endl;
// 1. 获取开始时的“CPU嘀嗒数”
clock_t start = clock();
// 2. 执行你的代码
heavy_work();
// 3. 获取结束时的“CPU嘀嗒数”
clock_t end = clock();
// 4. 计算时间差 (秒)
double cpu_time_taken = double(end - start) / double(CLOCKS_PER_SEC);
cout << "CPU 耗时: " << cpu_time_taken << " 秒" << endl;
return 0;
}
</pre></div>
<p><strong>“手把手”终端模拟 (结果因机器和编译优化而异):</strong></p>
<div class="jb51code"><pre class="brush:cpp;">PS C:\MyCode> g++ clock_example.cpp -o clock_example.exe -O0 # -O0 关闭优化
PS C:\MyCode> .\clock_example.exe
--- 测试 C 风格 <ctime> (clock_t) ---
每秒“嘀嗒”数 (CLOCKS_PER_SEC): 1000
CPU 耗时: 1.156 秒
</pre></div>
<p><strong>缺点:</strong> 精度不高,且<strong>无法</strong>测量“等待”时间。</p>
<p class="maodian"></p><h2>第二部分:现代 C++std::chrono(“高精度电子秒表”)</h2>
<p><code>std::chrono</code> 库 (C++11) 是现代C++的<strong>黄金标准</strong>。它提供了高精度时钟和时间单位(纳秒、微秒、毫秒等)。</p>
<p><strong>核心步骤:</strong></p>
<ol><li>包含 <code><chrono></code>。</li><li>使用 <code>auto start = std::chrono::high_resolution_clock::now();</code> 获取<strong>当前挂钟时间点</strong>。</li><li>使用 <code>auto end = std::chrono::high_resolution_clock::now();</code> 获取<strong>结束时间点</strong>。</li><li>计算差值:<code>end - start</code>,得到一个 <code>duration</code> (时间段) 对象。</li><li>使用 <code>std::chrono::duration_cast</code> 将这个 <code>duration</code> 对象转换为你想要的单位(如毫秒)。</li></ol>
<p><strong><code>chrono_example.cpp</code> (推荐用法)</strong></p>
<div class="jb51code"><pre class="brush:cpp;">#include <iostream>
#include <chrono> // 1. 包含 C++11 时间库
#include <thread> // 2. 包含线程库 (用来演示“等待”)
using namespace std;
// 使用 using 来简化类型名 (可选,但推荐)
using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::duration;
using std::chrono::milliseconds;
using std::chrono::microseconds;
// 耗时函数 (包含工作和等待)
void work_and_sleep() {
// 模拟 CPU 工作
for(long i = 0; i < 3000000000L; ++i) {}
// 模拟 I/O 等待或休眠 (500毫秒)
cout << "(正在休眠 500 毫秒...)" << endl;
std::this_thread::sleep_for(milliseconds(500));
}
int main() {
cout << "--- 测试 现代 C++ <chrono> ---" << endl;
// 1. 获取开始时间点
auto start_time = high_resolution_clock::now();
// 2. 执行你的代码
work_and_sleep();
// 3. 获取结束时间点
auto end_time = high_resolution_clock::now();
// 4. 计算时间差
// 结果是一个 duration 对象
auto duration_total = duration_cast<milliseconds>(end_time - start_time);
// 5. 打印结果
cout << "总耗时 (挂钟时间): " << duration_total.count() << " 毫秒" << endl;
// 也可以转换为其他单位
auto duration_us = duration_cast<microseconds>(end_time - start_time);
cout << "(即 " << duration_us.count() << " 微秒)" << endl;
return 0;
}
</pre></div>
<p><strong>“手把手”终端模拟 (结果因机器而异):</strong></p>
<div class="jb51code"><pre class="brush:cpp;">PS C:\MyCode> g++ chrono_example.cpp -o chrono_example.exe -std=c++11 -O0 -pthread
PS C:\MyCode> .\chrono_example.exe
--- 测试 现代 C++ <chrono> ---
(正在休眠 500 毫秒...)
总耗时 (挂钟时间): 1658 毫秒
(即 1658390 微秒)
</pre></div>
<p><strong>顿悟时刻:</strong> 结果 <code>1658</code> 毫秒,约等于 <code>1158</code> 毫秒 (CPU工作) + <code>500</code> 毫秒 (休眠)。<code><chrono></code> <strong>正确地</strong>测量了<strong>所有</strong>流逝的时间!</p>
<p class="maodian"></p><h2>第三部分:新手的“头号噩梦”——clock()vs<chrono></h2>
<p>让我们把两个“秒表”放在<strong>同一个</strong>程序里,测量<strong>同一个</strong>函数,看看它们的区别。</p>
<p><strong><code>comparison.cpp</code> (关键对比)</strong></p>
<div class="jb51code"><pre class="brush:cpp;">#include <iostream>
#include <ctime>
#include <chrono>
#include <thread>
using namespace std;
// (函数 work_and_sleep 同上)
void work_and_sleep() {
for(long i = 0; i < 3000000000L; ++i) {}
cout << "(正在休眠 500 毫秒...)" << endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
int main() {
// --- 1. <chrono> 计时 (挂钟时间) ---
auto start_chrono = std::chrono::high_resolution_clock::now();
// --- 2. <ctime> 计时 (CPU 时间) ---
clock_t start_clock = clock();
// --- 3. 执行同一个函数 ---
cout << "--- 正在执行 work_and_sleep... ---" << endl;
work_and_sleep();
cout << "--- 执行完毕 ---" << endl;
// --- 4. 获取 <ctime> 结果 ---
clock_t end_clock = clock();
double cpu_time = double(end_clock - start_clock) / double(CLOCKS_PER_SEC);
// --- 5. 获取 <chrono> 结果 ---
auto end_chrono = std::chrono::high_resolution_clock::now();
auto wall_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end_chrono - start_chrono);
// --- 6. 打印对比 ---
cout << "\n--- 结果对比 ---" << endl;
cout << "CPU 秒表 (clock()): " << cpu_time * 1000 << " 毫秒" << endl;
cout << "电子秒表 (chrono): " << wall_time_ms.count() << " 毫秒" << endl;
return 0;
}
</pre></div>
<p><strong>“手把手”终端模拟 (结果因机器而异):</strong></p>
<div class="jb51code"><pre class="brush:cpp;">PS C:\MyCode> g++ comparison.cpp -o comparison.exe -std=c++11 -O0 -pthread
PS C:\MyCode> .\comparison.exe
--- 正在执行 work_and_sleep... ---
(正在休眠 500 毫秒...)
--- 执行完毕 ---
--- 结果对比 ---
CPU 秒表 (clock()): 1162 毫秒 # <-- 只有 CPU 工作的时间!
电子秒表 (chrono): 1663 毫秒 # <-- CPU 工作 (1162) + 休眠 (500)
</pre></div>
<p><strong>“黄金法则”:</strong></p>
<ul><li>当你想知道“<strong>我的代码占用了多少 CPU 资源?</strong>”(用于算法分析),<code>clock()</code> 可以用(但 <code><chrono></code> 也有 CPU 时钟)。</li><li>当你想知道“<strong>用户等了多久?</strong>”(从按下按钮到看到结果),<strong>永远</strong>使用 <code>std::chrono::high_resolution_clock</code>!这几乎是你 99% 情况下想要的答案。</li></ul>
<p class="maodian"></p><h2>第四部分:“X光透 视”——观察时间点</h2>
<p><code>auto start_time = high_resolution_clock::now();</code> 返回的对象是一个 <code>time_point</code>(时间点)。它通常只是一个(非常大的)数字,代表从某个“纪 元”(比如1970年1月1日,或计算机启动时)到现在的纳秒数。</p>
<p class="maodian"></p><h3>“X光”实战(基于chrono_example.cpp)</h3>
<ol><li><strong>设置断点:</strong>
<ul><li>在 <code>main</code> 函数的<strong>第31行</strong>(<code>auto start_time = ...</code>)<strong>之后</strong>。</li><li>在 <code>main</code> 函数的<strong>第36行</strong>(<code>auto end_time = ...</code>)<strong>之后</strong>。</li></ul></li><li><strong>启动调试 (F5)。</strong></li><li><strong>第一次“冻结” (第31行后):</strong><ul><li><strong>观察“变量”(VARIABLES)窗口:</strong> 找到 <code>start_time</code>。</li><li><strong>展开 <code>start_time</code></strong>:你会看到它内部可能有一个成员,比如 <code>_M_time_since_epoch</code> 或 <code>_Rep</code> (内部表示)。</li><li><strong>你会看到:</strong> 一个<strong>巨大</strong>的数字,例如 <code>1678886400123456789</code> (纳秒)。</li></ul></li><li><strong>继续执行 (F5)。</strong></li><li><strong>第二次“冻结” (第36行后):</strong><ul><li><strong>观察“变量”窗口:</strong> 找到 <code>end_time</code>。</li><li><strong>展开 <code>end_time</code></strong>:</li><li><strong>你会看到:</strong> 另一个<strong>巨大</strong>的数字,例如 <code>1678886401783456789</code>。</li></ul></li><li><strong>(关键!)“监视” (WATCH) 窗口:</strong><ul><li><strong>动作:</strong> 在“监视”窗口中,添加<strong>这个</strong>表达式:<br /><code>std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count()</code></li><li><strong>你会看到:</strong> <code>1660</code> (或者你的实际测量值)!</li><li><strong>顿悟时刻:</strong> 调试器向你展示了 <code>chrono</code> 库是如何通过两个“时间点”相减,得到一个“时间段”,并最终转换为你需要的单位的。</li></ul></li></ol>
<p class="maodian"></p><h2>动手试试!(终极挑战:你的“排序分析器”)</h2>
<p>现在,你来当一次“算法分析师”。</p>
<p><strong>任务:</strong></p>
<ol><li>“激活” <code>iostream</code>, <code>vector</code>, <code>algorithm</code> (为了 <code>std::sort</code>), <code>chrono</code> 和 <code>random</code> (为了生成随机数)。</li><li>创建一个<strong>非常大</strong>的 <code>vector<int></code> (例如,<code>1,000,000</code> 个元素),并用<strong>随机</strong>数字填充它。</li><li>使用 <strong><code>std::chrono</code></strong>(高精度电子秒表):<ul><li>在调用 <code>std::sort</code> <strong>之前</strong>,获取“开始时间”。</li><li>调用 <code>std::sort(myVector.begin(), myVector.end());</code>。</li><li>在 <code>std::sort</code> <strong>之后</strong>,获取“结束时间”。</li></ul></li><li>计算时间差,并<strong>以毫秒 (milliseconds)</strong> 为单位,<strong>打印</strong>出排序一百万个随机整数所花费的时间。</li></ol>
<p><strong><code>sort_timer.cpp</code> (你的 TODO):</strong></p>
<div class="jb51code"><pre class="brush:cpp;">#include <iostream>
#include <vector>
#include <algorithm> // 需要 std::sort
#include <chrono> // 需要计时
#include <random> // 需要随机数
using namespace std;
// (使用 using std::chrono::... 来简化)
using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::milliseconds;
int main() {
// --- 1 & 2: 创建并填充 100 万个随机数 ---
const int N = 1000000;
vector<int> numbers;
numbers.reserve(N); // 预分配内存,提高效率
std::random_device rd;// 随机数种子源
std::mt19937 gen(rd()); // 随机数引擎
std::uniform_int_distribution<> distrib(1, N); // 分布范围
cout << "正在生成 " << N << " 个随机数..." << endl;
for (int i = 0; i < N; ++i) {
numbers.push_back(distrib(gen));
}
cout << "生成完毕。" << endl;
// --- TODO 3: 计时 ---
cout << "\n--- 开始排序... ---" << endl;
// auto startTime = ...;
// std::sort(... , ...); // 执行排序
// auto endTime = ...;
// --- TODO 4: 计算并打印 ---
// auto timeTaken_ms = ...;
// cout << "排序 " << N << " 个元素耗时: "
// << timeTaken_ms.count() << " 毫秒" << endl;
return 0;
}
</pre></div>
<blockquote><p>这个挑战让你实践了如何使用 std::chrono 来测量一个<strong>真实</strong>、<strong>有意义</strong>的计算任务(std::sort)的性能。完成它,你就掌握了C++中最重要、最准确的计时工具!</p></blockquote>
<p>以上就是在C++中测量代码执行时间的两种方法的详细内容,更多关于C++测量代码执行时间的资料请关注琼殿技术社区其它相关文章!</p>
<div class="art_xg">
<b>您可能感兴趣的文章:</b><ul><li>C++实时控制系统代码执行时间优化深度指南</li><li>c++ chrono 获取当前时间的实现代码</li><li>C++实现统计代码运行时间的示例详解</li><li>C/C++实现获取系统时间的示例代码</li><li>C++实现统计代码运行时间计时器的简单实例</li></ul>
</div>
</div>
<!--endmain-->
頁:
[1]