2011-05-22 55 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