Lua内部函数vs模块级函数

joh*_*age 10 lua

对于另一个函数内部的函数,Lua是否在每次调用外部函数时"实例化"内部函数?如果是这样,bar()下面的代码会表现得差foo()吗?

local function a()
  print 'a'
end

function foo()
  a()
end

function bar()
  function b()
    print 'b'
  end

  b()
end
Run Code Online (Sandbox Code Playgroud)

JUS*_*ION 17

测试案例1:ab两个全球性的,没有嵌入.

$ cat junk.lua ; time lua junk.lua
function a(n)
    return n + 1
end

function b(n)
    return a(n)
end

for c = 1, 10000000 do
    b(c)
end


real    0m1.743s
user    0m1.740s
sys 0m0.000s
Run Code Online (Sandbox Code Playgroud)

用户时间:1.74秒.

测试用例2:a本地,b全局,无嵌入.

local function a(n)
    return n + 1
end

function b(n)
    return a(n)
end

for c = 1, 10000000 do
    b(c)
end


real    0m1.388s
user    0m1.390s
sys 0m0.000s
Run Code Online (Sandbox Code Playgroud)

用户时间1.39秒.

测试用例3:a并且b都是本地的,没有嵌入.

$ cat junk.lua ; time lua junk.lua
local function a(n)
    return n + 1
end

local function b(n)
    return a(n)
end

for c = 1, 10000000 do
    b(c)
end


real    0m1.194s
user    0m1.200s
sys 0m0.000s
Run Code Online (Sandbox Code Playgroud)

用户时间1.2秒.

测试案例4:a嵌入式b,a全局式,b本地式.

$ cat junk.lua ; time lua junk.lua
local function b(n)
    function a(n)
        return n + 1
    end

    return a(n)
end

for c = 1, 10000000 do
    b(c)
end


real    0m2.804s
user    0m2.790s
sys 0m0.000s
Run Code Online (Sandbox Code Playgroud)

用户时间:2.79秒.(!)

测试用例5:a嵌入式b,均为本地.

$ cat junk.lua ; time lua junk.lua
local function b(n)
    local function a(n)
        return n + 1
    end

    return a(n)
end

for c = 1, 10000000 do
    b(c)
end


real    0m2.540s
user    0m2.530s
sys 0m0.000s
Run Code Online (Sandbox Code Playgroud)

用户时间:2.53秒.

结果摘要:

  1. 编写测试以确认或否认对性能的直觉很容易.你应该这样做,而不是依赖众包的答案.(你看,人群经常是错的.)
  2. 使函数局部而不是全局函数对函数调用开销具有显着的积极影响.(当这两个函数都是本地函数时,这组测试用例大约要好30%.)
  3. 在另一个函数中嵌入函数会对函数调用开销产生严重的负面影响.(当这两个函数都是本地函数时,这组测试用例大约差110%.)
  4. 我是否提到测试可能是一个很好的想法,只有信任人群?


pon*_*zao 5

bar会慢一些因为你每次都在创建一个新的函数对象.如果要在函数内声明函数,可能需要返回闭包.

local bar = function()
  local f = function()
    -- Lots of stuff...
  end
  local g = function()
    -- Also lots of stuff
  end
  return function()
    -- Do something with f and g...
  end
end

local created_f = bar()
created_f()
created_f()  -- Now you can skip the function initialization.
Run Code Online (Sandbox Code Playgroud)