为何数组增量函数f1比f2运行慢1.76倍?
为什么f1比f2在默认GCC编译下慢近一倍?
问题背景
两个功能完全一致的函数f1和f2,均接收数值T与初始全为0的整数数组arr,最终将数组每个元素设置为T。但在默认GCC编译(无优化)下,f1的运行速度比f2慢约1.76倍,运行输出如下:
➜ Desktop gcc timing-difference.c && ./a.out 1000000000 16 -----> Running f1 <------- Time taken: 15.511 seconds -----> Running f2 <------- Time taken: 8.887 seconds
函数核心逻辑差异:
- f1直接对数组元素
arr[i]做T次自增 - f2先将
arr[i]读到临时变量tmp,对tmp做T次自增后,再写回arr[i]
调换函数调用顺序或多次运行,结果一致;启用-O2优化后,两者耗时均为0.000秒。
性能差异的核心原因
1. 内存访问开销的本质区别
- f1的内存行为:每次
arr[i] += 1都要执行「从内存/缓存读取arr[i] → CPU寄存器自增 → 写回内存/缓存」的完整流程。T=10⁹次循环意味着这个读写操作要重复10⁹次——即便arr[i]能被CPU缓存命中,每次自增的写操作也需要等待缓存的写回周期,累积的开销非常大。 - f2的内存行为:仅在循环前后各做1次内存操作:先把
arr[i]读到局部变量tmp(tmp会被编译器分配到CPU寄存器,属于高速区域),然后对tmp的10⁹次自增完全在寄存器内完成,没有任何内存读写开销;最后只需要把tmp的值一次性写回arr[i]。
2. 默认编译(-O0)的特性放大了差异
GCC默认的-O0选项会禁用几乎所有优化,严格保证代码执行逻辑与源码一一对应:
- 对于f1,编译器不会将
arr[i]临时缓存到寄存器中,必须严格执行每次循环的内存读写操作。 - 对于f2,
tmp作为局部变量,编译器会优先分配到CPU寄存器,自增操作全程在寄存器内完成,没有额外内存开销。
3. 优化后差异消失的原因
当启用-O2优化时,编译器会识别出「对初始值为0的变量做T次自增,等价于直接赋值为T」,直接将两个函数的逻辑优化为arr[i] = T,因此两者执行效率完全一致,耗时趋近于0。
内容的提问来源于stack exchange,提问作者smilingbuddha
相关产品推荐
相关产品推荐

