0Pricing
C++ Academy · 课时

测量代码性能

使用 chrono 进行基准测试

测量代码性能 是 CoddyKit 上的免费 C++ Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C++ Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C++ Academy 课程共包含 4 节课。

为什么进行基准测试

测量代码运行所需的时间有助于您找到瓶颈并验证优化效果。使用<chrono>可以获得可移植且类型安全的计时功能。

  • 在优化之前先进行测量。
  • 使用稳定的时钟来获得可靠的时间间隔。
#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    auto start = steady_clock::now();
    auto end = steady_clock::now();
    std::cout << "Timed a block: " << ((end - start).count() >= 0) << '\n';
    return 0;
}

基本模式

基准测试模式始终相同:在工作开始前捕获now(),运行工作,在工作结束后再次捕获now(),然后计算差值。

#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    auto start = steady_clock::now();
    long sum = 0;
    for (int i = 0; i < 100000; ++i) sum += i;
    auto end = steady_clock::now();
    std::cout << "Sum: " << sum << ", elapsed >= 0: " << ((end - start).count() >= 0) << '\n';
    return 0;
}

选择单位

选择适合工作负载的单位。快速循环使用microseconds或nanoseconds,较大的任务使用milliseconds。

#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    auto start = steady_clock::now();
    long sum = 0;
    for (int i = 0; i < 500000; ++i) sum += i;
    auto end = steady_clock::now();
    auto us = duration_cast<microseconds>(end - start);
    std::cout << "Result: " << sum << ", us non-negative: " << (us.count() >= 0) << '\n';
    return 0;
}

浮点计时

如果要显示带小数的人类可读秒数,请使用duration<double>,以保留亚秒级精度。

#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    auto start = steady_clock::now();
    long sum = 0;
    for (int i = 0; i < 200000; ++i) sum += i % 7;
    auto end = steady_clock::now();
    duration<double> secs = end - start;
    std::cout << "Computed " << sum << ", seconds >= 0: " << (secs.count() >= 0) << '\n';
    return 0;
}

可复用的计时器

将这种模式封装在一个小型辅助工具中,这样您就可以简洁地测量任何可调用对象,避免重复编写代码。

#include <iostream>
#include <chrono>

long long timeWork() {
    using namespace std::chrono;
    auto s = steady_clock::now();
    long acc = 0;
    for (int i = 0; i < 100000; ++i) acc += i;
    auto e = steady_clock::now();
    return duration_cast<microseconds>(e - s).count();
}

int main() {
    std::cout << "Microseconds non-negative: " << (timeWork() >= 0) << '\n';
    return 0;
}

避免死代码消除

编译器可能会删除结果未被使用的工作,从而破坏基准测试。请始终使用计算结果,例如打印结果或将其累加到一个可见变量中。

#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    auto s = steady_clock::now();
    volatile long sink = 0;
    for (int i = 0; i < 100000; ++i) sink += i;
    auto e = steady_clock::now();
    std::cout << "Sink used: " << (sink > 0) << ", elapsed >= 0: " << ((e - s).count() >= 0) << '\n';
    return 0;
}

预热运行

由于缓存和延迟初始化,第一次运行可能较慢。测量前请执行一次预热,以获得更稳定的数据。

#include <iostream>
#include <chrono>

long work() {
    long a = 0;
    for (int i = 0; i < 50000; ++i) a += i;
    return a;
}

int main() {
    using namespace std::chrono;
    work();
    auto s = steady_clock::now();
    long r = work();
    auto e = steady_clock::now();
    std::cout << r << " measured, ok: " << ((e - s).count() >= 0) << '\n';
    return 0;
}

多次运行取平均值

单次测量会受到噪声影响。多次运行工作,累加经过的时长,然后求平均值,以获得稳定的结果。

#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    long long total = 0;
    const int runs = 5;
    for (int r = 0; r < runs; ++r) {
        auto s = steady_clock::now();
        long acc = 0;
        for (int i = 0; i < 100000; ++i) acc += i;
        auto e = steady_clock::now();
        total += duration_cast<microseconds>(e - s).count();
    }
    std::cout << "Average us non-negative: " << ((total / runs) >= 0) << '\n';
    return 0;
}

比较两种方法

比较不同实现时,基准测试非常有用。请用相同方式分别计时,然后比较所得的时长。

#include <iostream>
#include <chrono>
#include <vector>

int main() {
    using namespace std::chrono;
    std::vector<int> v;
    auto s1 = steady_clock::now();
    for (int i = 0; i < 10000; ++i) v.push_back(i);
    auto e1 = steady_clock::now();
    v.clear();
    v.reserve(10000);
    auto s2 = steady_clock::now();
    for (int i = 0; i < 10000; ++i) v.push_back(i);
    auto e2 = steady_clock::now();
    std::cout << "Both timed: " << (((e1 - s1).count() >= 0) && ((e2 - s2).count() >= 0)) << '\n';
    return 0;
}

注意计时分辨率

如果测量的工作短于时钟的一次滴答,您可能会读到零。请将这项工作循环执行足够多次,使总时长超过时钟分辨率。

#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    auto s = steady_clock::now();
    int x = 1 + 1;
    auto e = steady_clock::now();
    auto ns = duration_cast<nanoseconds>(e - s).count();
    std::cout << "x=" << x << ", tiny work may read low: " << (ns >= 0) << '\n';
    return 0;
}

报告结果

请将最终时长转换为易读的单位并输出。请让已消耗的结果保持可见,以免优化器移除这项工作。

#include <iostream>
#include <chrono>

int main() {
    using namespace std::chrono;
    auto s = steady_clock::now();
    long acc = 0;
    for (int i = 0; i < 300000; ++i) acc += (i * 3) % 11;
    auto e = steady_clock::now();
    auto ms = duration_cast<milliseconds>(e - s).count();
    std::cout << "acc=" << acc << ", ms >= 0: " << (ms >= 0) << '\n';
    return 0;
}

快速检查

请测试您对基准测试陷阱的理解。

回顾

您已经学会了如何使用 <chrono> 为代码进行基准测试:

  • 在前后分别捕获 steady_clock::now(),然后求差
  • 使用 duration_cast 选择合适的单位
  • 预热、对多次运行求平均,并使用结果来阻止删除无效代码
  • 注意极小工作负载下的时钟分辨率

接下来,您将探索 C++20 的日历和时区类型。

常见问题解答

「测量代码性能」课时是免费的吗?

是的 — 「测量代码性能」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C++ Academy 课程的其余内容,请升级到 CoddyKit PRO。 C++ Academy 课程共包含 4 节课。

「测量代码性能」这节课中我会学到什么?

使用 chrono 进行基准测试 你通过在浏览器中直接运行的动手代码来练习 C++ Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C++ Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C++ Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「测量代码性能」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C++ Academy 课中编写并运行代码吗?

能。每节 C++ Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 时长与时钟
  2. 时间点
  3. 测量代码性能
  4. 日历与时区
← 返回 C++ Academy