Julia全局变量定义位置为何导致程序执行时间出现数量级差异
问题背景
- 第一版代码将全局变量定义在
main函数内部,设备实测运行耗时约150ms,代码如下:
using BenchmarkTools function main() global solution = 0 global a = big"1" global b = big"1" global c = big"0" global total = 0 while a < 100 while b < 100 c = a^b s = string(c) total = 0 for i in 1:length(s) total = total + Int(s[i]) - 48 end if total > solution global solution = total end global b = b + 1 end global b = 1 global a = a + 1 end end @elapsed begin main() end #run @elapsed twice to ignore compilation overhead t = @elapsed main() print("Solution: ", solution) t = t * 1000; print("\n\nProgram completed in ", round.(t; sigdigits=5), " milliseconds.")
- 调整代码将全局变量定义挪到文件顶层后,同设备测得运行耗时仅0.0042ms,修改后代码如下:
using BenchmarkTools global solution = 0 global a = big"1" global b = big"1" global c = big"0" global total = 0 function main() while a < 100 while b < 100 c = a^b s = string(c) total = 0 for i in 1:length(s) total = total + Int(s[i]) - 48 end if total > solution global solution = total end global b = b + 1 end global b = 1 global a = a + 1 end end @elapsed begin main() end #run @elapsed twice to ignore compilation overhead t = @elapsed main() print("Solution: ", solution) t = t * 1000; print("\n\nProgram completed in ", round.(t; sigdigits=5), " milliseconds.")
- 核心疑问:仅修改全局变量定义位置,为何运行耗时出现大幅度下降?
根本原因
这个夸张的耗时差距和全局变量的性能特性没有直接关系,纯粹是代码修改带来的逻辑bug,导致第二次计时的main调用完全没有执行计算逻辑:
- 第一版代码中,
main函数开头就写了全局变量重置逻辑:每次调用main,都会把a、b、solution等全局变量重新赋值为初始值。所以第一次预热调用main、第二次正式计时调用main时,两次都是从a=1、b=1的初始状态开始完整跑完所有双重循环,测得的150ms是真实的计算耗时。 - 第二版代码把全局变量的初始化语句挪到了顶层,
main函数内部没有任何重置变量的逻辑。第一次预热调用main时,确实会完整跑完所有循环,跑完之后全局变量a的值已经累加到100,solution也已经算出了最终结果。等到第二次调用main做正式计时时,进入函数第一个判断就是while a < 100,此时a的值已经是100,循环条件直接不成立,函数什么计算都没做就直接返回了,测得的0.0042ms只是函数空跑的调用开销,根本不是实际计算的耗时。
补充验证:如果在第二版第二次计时前手动把a、b、solution等全局变量重置为初始值,再跑计时会发现实际耗时和第一版基本没有差别,甚至可能因为全局变量没有类型标注比第一版稍慢——Julia中无类型约束的全局变量本身确实存在类型不稳定导致的性能损耗,但这个案例里的极端耗时差和这个特性无关。
内容的提问来源于stack exchange,提问作者MFerguson
相关产品推荐
相关产品推荐

