2011-05-22 62 views
8

对于另一个函数内部的函数,Lua是否在每次调用外部函数时都“实例化”内部函数?如果是这样,在下面的代码中bar()的性能会比foo()差吗?Lua内部函数与模块级函数

local function a() 
    print 'a' 
end 

function foo() 
    a() 
end 

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

    b() 
end 

回答

15

测试案例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 

用户时间:1.74s

测试案例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 

用户时间1.39s

测试案例3:ab都是本地的,没有嵌入。

$ 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 

用户时间1.2S

测试案例4:a嵌入ba全局,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 

用户时间:2.79s。 (!)

测试案例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 

用户时间:2.53s

结果概要:

  1. 可以很容易地编写测试,以证实或否认有关性能的直觉。你可能应该这样做,而不是依靠人群寻找答案。 (你会发现人群往往是错误的。)
  2. 使函数局部而不是全局对函数调用开销具有显着的正面影响。 (当这两个函数都是本地时,在这组测试用例中约好30%)。
  3. 将函数嵌入到另一个函数中会对函数调用开销造成严重的负面影响。 (当这两个函数都是本地的时候,这组测试用例差了大约110%)。
  4. 难道我提到测试可能是一个好主意吗?
+1

谢谢!我会测试,但我不知道如何。我想这应该是我的第一个问题。 – johncage 2011-05-22 19:02:58

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. 
+0

你打败了我,因为我做了这个冗长的方式。 :D +1 – 2011-05-22 09:51:28

+0

我实际上做了一些基准检验来验证一些事情,但意识到原始海报可能应该自己做(如你在答案中所述)。为你+1还有一个详细的答案。 – ponzao 2011-05-22 09:55:05

+0

我希望我可以给你另外一个代码+1并展示如何使用闭包。 (我也希望自己能想到显示关闭的用法。) – 2011-05-23 02:05:59