Featured image of post 需要“局部变量化”全局函数么?

需要“局部变量化”全局函数么?

前言

  在很多的 Lua 语言相关的著作中都强调,在代码头部将代码里使用到的全局函数或者全局库局部变量化,将大大提升代码的执行效率。
  举个栗子,Roberto Ierusalimschy《Lua Programming Gems》 的第二章 Lua Performance Tips 提到:

 除了一些明显的地方外,另有几处也可使用局部变量,可以助你挤出更多的性能。比如,如果在很长的循环里调用函数,可以先将这个函数赋值给一个局部变量。这个代码:

1
2
3
for i = 1, 1000000 do
    local x = math.sin(i)
end

比如下代码慢 30%:

1
2
3
4
local sin = math.sin
for i = 1, 1000000 do
  local x = sin(i)
end

烦恼

  起初我也坚信这一点,并严格的执行。但对于一个以前一直使用 OOP 语言的程序猿来说,这样做很痛苦。
  首先,这给我的编码带来了额外的麻烦。我必须在编码完成后进行 review、定义和替换,或者在编码过程中用到全局库和函数时就立即在头部定义局部变量。
  其次,这样编码实在是有些丑陋,违反了我的代码审美。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
local bit = require "bit"
local sub = string.sub
local tcp = ngx.socket.tcp
local strbyte = string.byte
local strchar = string.char
local strfind = string.find
local format = string.format
local strrep = string.rep
local null = ngx.null
local band = bit.band
local bxor = bit.bxor
local bor = bit.bor
local lshift = bit.lshift
local rshift = bit.rshift
local tohex = bit.tohex
local sha1 = ngx.sha1_bin
local concat = table.concat
local unpack = unpack
local setmetatable = setmetatable
local error = error
local tonumber = tonumber

   Oh no ~~ 这样的代码头部实在是丑陋的让我这样的强迫症患者不忍直视。我开始思考,这样做能够提升多少性能呢?是否真的有必要呢?

测试

   首先我要测试一下,这样做性能提升真的很大么?
   测试代码引用自 《Lua Programming Gems》 里的示例代码,为了使结果看起来更明显,我将循环次数提升了100倍。

   测试文件 test1.lua 的代码:

1
2
3
for i = 1, 100000000 do
  local x = math.sin(i)
end

   测试文件 test2.lua 的代码:

1
2
3
4
local sin = math.sin
for i = 1, 100000000 do
  local x = sin(i)
end

Lua 5.2 测试

  我们先用 Lua 5.2 测试下两个文件的执行效率:

Lua 5.2 测试结果

  看起来前辈们说的很正确,使用局部变量执行效率真的提高了30%以上。

Lua 5.3 测试

  我们再用最新的 Lua 5.3 测试下两个文件的执行效率:

Lua 5.3 测试结果

  看起来 Lua 5.3 对这方面做了专门的优化,差距已经不是那么明显了。

Luajit 2.1 测试

  我们再用最新的 Luajit 2.1 测试下两个文件的执行效率:

Luajit 2.1 测试结果

  被结果吓了一跳,Luajit 2.1 真是逆天啊,比 Lua 5.3 快了几个数量级。
  由于 Luajit 的实现机制和优化,两个文件的执行时间已经没有区别。

结论

对于 Lua 5.2

  使用局部变量化执行效率提升了 30% 以上,效果非常明显。编码时仍应该坚持使用全局函数局部变量化。

对于 Lua 5.3

  执行效率提升了不到 4%,几乎没有效果。如有强迫症,可继续使用全局函数局部变量化,一般程序猿建议无视,按自己的习惯编码。

对于 Luajit 2.1

  执行效率毫无差别。可按自己的习惯编码。

结语

  这真是一个让人欣喜的结果,由于 Openresty 中使用的是 luajit,我终于可以忽视这个规则,自由的编码了。
  同时也可以看出,Lua 正在不断的进步和完善。

  编程应该是快乐的,不要让任何事情剥夺了你的编程乐趣!