为什么空for循环运行速度比包含x++操作的for循环更慢?
空循环耗时更长的核心原因
你观察到的现象仅会出现在关闭编译器优化的场景下:如果开启-O2及以上优化,无副作用的空循环会被编译器直接删除,不可能出现8.5秒的耗时。
在无优化的前提下,该现象是现代CPU的微架构特性导致的,核心原因有两个:
1. 数据依赖导致的流水线停顿
两段代码的循环控制逻辑都存在严格的串行数据依赖,无优化生成的汇编伪代码如下:
add eax, 1 ; 对应++i,eax存i的值 cmp eax, esi ; 对应i < t,esi存t的值 jb loop_start ; 满足条件则跳转回循环开头
这三条指令是强依赖关系:cmp必须等待add的计算结果才能执行,jb必须等待cmp的标志位结果才能执行,形成了长度为3的指令依赖链。现代CPU虽然支持指令级并行,但无法并行执行有依赖的指令,空循环场景下CPU的多个执行单元处于闲置状态,每轮循环必须等待整个依赖链执行完成才能进入下一轮。
而带x++的代码,多出来的自增操作是完全独立于i的计算的:
add rcx, 1 ; 对应x++,rcx存x的值,和i的计算无任何依赖 add eax, 1 cmp eax, esi jb loop_start
CPU的乱序执行单元可以将add rcx,1插入到add eax,1和cmp eax,esi的等待间隙执行,这条额外指令几乎不会增加每轮循环的耗时。
2. 超短循环的微架构开销
多数现代CPU的前端对只有2~3条指令的超短循环存在特殊的处理开销:部分微架构的循环缓冲区无法适配极短的指令序列,或者取指单元的带宽无法被短循环有效利用,反而会引入额外的流水线气泡。增加了x++指令后,循环体长度刚好避开了这类微架构的特殊开销,最终整体耗时反而更短。
注意:该现象和你使用的CPU微架构强相关,并非通用的规律。如果要做准确的性能测试,必须开启编译优化,同时要保证待测试代码有可观测的副作用,避免被编译器直接优化消除。
内容的提问来源于stack exchange,提问作者Mojtaba Valizadeh
相关产品推荐
相关产品推荐

