C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++测量代码执行时间

在C++中测量代码执行时间的两种方法

作者:weixin_pk138132

在C++中,编写代码只是第一步,衡量代码的效率同样重要,你如何知道你的 sort 算法比同事写的快?或者你的新功能导致了多少性能下降?你需要一个秒表来精确测量代码的执行时间,本文给大家介绍了在C++中测量代码执行时间的两种方法,需要的朋友可以参考下

在C++中,编写代码只是第一步,衡量代码的“效率”同样重要。你如何知道你的 sort 算法比同事写的快?或者你的新功能导致了多少性能下降?你需要一个“秒表”来精确测量代码的执行时间。

在C++(及C语言)中,你有两种主要的“秒表”:

C 风格 “CPU 秒表” (<ctime>/clock())

现代 C++ 风格 “高精度电子秒表” (<chrono>)

在本教程中,你将学会:

前置知识说明 (100% 自洽):

第一部分:C 风格clock()(“CPU 秒表”)

clock() 函数在 <ctime> 库中。它返回程序启动到当前时刻为止,CPU 花在你程序上的“嘀嗒数”(Clock Ticks)。

核心步骤:

  1. 包含 <ctime>
  2. 在代码开始前,调用 clock_t start = clock(); 记录“开始嘀嗒数”。
  3. 在代码结束后,调用 clock_t end = clock(); 记录“结束嘀嗒数”。
  4. 计算差值 double(end - start),然后除以 CLOCKS_PER_SEC (一个系统常量,表示“每秒多少嘀嗒数”),得到秒数

clock_example.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;
}

“手把手”终端模拟 (结果因机器和编译优化而异):

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 秒

缺点: 精度不高,且无法测量“等待”时间。

第二部分:现代 C++std::chrono(“高精度电子秒表”)

std::chrono 库 (C++11) 是现代C++的黄金标准。它提供了高精度时钟和时间单位(纳秒、微秒、毫秒等)。

核心步骤:

  1. 包含 <chrono>
  2. 使用 auto start = std::chrono::high_resolution_clock::now(); 获取当前挂钟时间点
  3. 使用 auto end = std::chrono::high_resolution_clock::now(); 获取结束时间点
  4. 计算差值:end - start,得到一个 duration (时间段) 对象。
  5. 使用 std::chrono::duration_cast 将这个 duration 对象转换为你想要的单位(如毫秒)。

chrono_example.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;
}

“手把手”终端模拟 (结果因机器而异):

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 微秒)

顿悟时刻: 结果 1658 毫秒,约等于 1158 毫秒 (CPU工作) + 500 毫秒 (休眠)。<chrono> 正确地测量了所有流逝的时间!

第三部分:新手的“头号噩梦”——clock()vs<chrono>

让我们把两个“秒表”放在同一个程序里,测量同一个函数,看看它们的区别。

comparison.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;
}

“手把手”终端模拟 (结果因机器而异):

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)

“黄金法则”:

第四部分:“X光透 视”——观察时间点

auto start_time = high_resolution_clock::now(); 返回的对象是一个 time_point(时间点)。它通常只是一个(非常大的)数字,代表从某个“纪 元”(比如1970年1月1日,或计算机启动时)到现在的纳秒数。

“X光”实战(基于chrono_example.cpp)

  1. 设置断点:
    • main 函数的第31行auto start_time = ...之后
    • main 函数的第36行auto end_time = ...之后
  2. 启动调试 (F5)。
  3. 第一次“冻结” (第31行后):
    • 观察“变量”(VARIABLES)窗口: 找到 start_time
    • 展开 start_time:你会看到它内部可能有一个成员,比如 _M_time_since_epoch_Rep (内部表示)。
    • 你会看到: 一个巨大的数字,例如 1678886400123456789 (纳秒)。
  4. 继续执行 (F5)。
  5. 第二次“冻结” (第36行后):
    • 观察“变量”窗口: 找到 end_time
    • 展开 end_time
    • 你会看到: 另一个巨大的数字,例如 1678886401783456789
  6. (关键!)“监视” (WATCH) 窗口:
    • 动作: 在“监视”窗口中,添加这个表达式:
      std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time).count()
    • 你会看到: 1660 (或者你的实际测量值)!
    • 顿悟时刻: 调试器向你展示了 chrono 库是如何通过两个“时间点”相减,得到一个“时间段”,并最终转换为你需要的单位的。

动手试试!(终极挑战:你的“排序分析器”)

现在,你来当一次“算法分析师”。

任务:

  1. “激活” iostream, vector, algorithm (为了 std::sort), chronorandom (为了生成随机数)。
  2. 创建一个非常大vector<int> (例如,1,000,000 个元素),并用随机数字填充它。
  3. 使用 std::chrono(高精度电子秒表):
    • 在调用 std::sort 之前,获取“开始时间”。
    • 调用 std::sort(myVector.begin(), myVector.end());
    • std::sort 之后,获取“结束时间”。
  4. 计算时间差,并以毫秒 (milliseconds) 为单位,打印出排序一百万个随机整数所花费的时间。

sort_timer.cpp (你的 TODO):

#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;
}

这个挑战让你实践了如何使用 std::chrono 来测量一个真实有意义的计算任务(std::sort)的性能。完成它,你就掌握了C++中最重要、最准确的计时工具!

以上就是在C++中测量代码执行时间的两种方法的详细内容,更多关于C++测量代码执行时间的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文