bigywater.tech
Rust · 67

Iterator 链的性能

「迭代器链和手写循环一样快」是 Rust 的著名说法。这篇不信传说:同一个计算写成链、for、下标 while、中间 Vec,在 release、debug 和各级 opt-level 下实测,再数分配次数,看这个说法成立的条件。

2.724 对 2.725 ms
release 下 1000 万个元素,链 对 for 循环
2.1×
debug 下链比 for 循环慢的倍数
5.6×
release 下中间 Vec 版本比链慢的倍数

release 下的对比

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
    链 2.724 ms | for 循环 2.725 ms | 下标 while 2.955 ms | 中间 Vec 15.150 ms | 结果相同: true

惰性与逐元素执行见Iterator 的惰性执行。

debug 下的对比

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
    链 6.522 ms | for 循环 3.154 ms | 下标 while 2.584 ms | 中间 Vec 11.728 ms | 结果相同: true

opt-level

实测 · 本机执行输出
  编译:成功
  opt-level=0:  链 63.168 ms | for 循环 31.122 ms | 下标 while 29.381 ms | 中间 Vec 121.602 ms | 结果相同: true
  编译:成功
  opt-level=1:  链 2.749 ms | for 循环 4.915 ms | 下标 while 2.747 ms | 中间 Vec 13.518 ms | 结果相同: true
  编译:成功
  opt-level=2:  链 3.338 ms | for 循环 3.154 ms | 下标 while 3.159 ms | 中间 Vec 12.286 ms | 结果相同: true
  编译:成功
  opt-level=3:  链 2.949 ms | for 循环 2.698 ms | 下标 while 2.966 ms | 中间 Vec 12.129 ms | 结果相同: true

Cargo 的 profile 配置见Cargo Profile。

中间 Vec 的代价

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
    惰性链:  alloc 0 realloc 0 申请字节 0  结果 16616700000
    中间 Vec: alloc 2 realloc 14 申请字节 1448544  结果 16616700000

filter 的 size_hint 见collect 类型推断。

分步演示

Iterator 链性能
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / rustc 1.98.1(brew)/ cargo 1.98.1;单个文件用 rustc 直接编译,需要依赖时用 cargo(经代理从 crates.io 下载);计时用 std::time::Instant,数字每次运行会有小幅抖动。每个数字是该进程内 3~5 次的最小值;不同次运行之间有噪声(同样配置下链与 for 可能差 10% 以上)
    • 没有验证:x86_64 机器、更复杂的链(zip/chain/flat_map)的汇编、字符串迭代、浮点求和(无法重排)、-C target-cpu=native
    京ICP备2026067502号-1京公网安备11010502063487号