lua table vs closure

  最近在重構本身寫的框架中的定時器模塊,須要把回調函數保存起來,大概以下:數據結構

function timer_mgr:save_timer( this,callback )
    return { this = this,callback = callback}
end

-- 建立新定時器
-- @after:延遲N秒後啓動定時器
-- @repeated:N秒循環
-- @this:回調對象
-- @callbakck:回調函數
function timer_mgr:new_timer( after,repeated,this,callback )
    local timer_id = self:next_id()
    self.timers[timer_id] = save_timer( this,callback )
end

function timer_mgr:do_timer( timer_id )
    local timer = self.timers[timer_id]

    -- 調用以前保存的定時器回調
    return timer.callback( timer.this )
end

正常狀況下,用table保存定時器的回調參數,畢竟lua中也沒有太多的數據結構能夠選擇。不過,咱們也能夠這樣用closure來保存:框架

function timer_mgr:save_timer( this,callback )
    return function()
        return callback( this )
    end
end

-- 建立新定時器
-- @after:延遲N秒後啓動定時器
-- @repeated:N秒循環
-- @this:回調對象
-- @callbakck:回調函數
function timer_mgr:new_timer( after,repeated,this,callback )
    local timer_id = self:next_id()
    self.timers[timer_id] = save_timer( this,callback )
end

function timer_mgr:do_timer( timer_id )
    local timer = self.timers[timer_id]

    -- 調用以前保存的定時器回調
    return timer()
end

這樣彷佛看起來更優雅更方便一些,不過,頻繁建立closure也是很消耗內存和cpu的,須要和table對比一下:函數

function test_table_object( this,cb )
    return { this = this,cb = cb }
end

function test_closure_object( this,cb )
    return function()
        return cb( this )
    end
end

local function cb()
    print("do nothing ...")
end

local max = 1000000

local table_mgr = {}
local closure_mgr = {}

function test_table()
    
    local beg_m = collectgarbage("count")
    local beg_tm = os.clock()

    for idx = 1,max do
        table_mgr[idx] = test_table_object( {},cb )
    end

    local end_m = collectgarbage("count")
    local end_tm = os.clock()

    print("table test",end_m - beg_m,end_tm - beg_tm)
end

function test_closure()
    
    local beg_m = collectgarbage("count")
    local beg_tm = os.clock()

    for idx = 1,max do
        table_mgr[idx] = test_closure_object( {},cb )
    end

    local end_m = collectgarbage("count")
    local end_tm = os.clock()

    print("closure test",end_m - beg_m,end_tm - beg_tm)
end

collectgarbage("stop")
collectgarbage("collect")

test_closure()
test_table()

這段代碼,分別在win10 - I3 cpu和debian7(虛擬機) - A8 cpu下測試:測試

closure test	117946.5	0.489
table test	125000.0	0.446

closure test	180446.5	0.75
table test	171875.0	0.72

能夠看到,table和closure的消耗其實都差很少。但closure在這個應用場景下就優雅得多,由於能夠很方便地傳更多的參數,好比:this

function timer_mgr:save_timer( this,callback,... )
    return function()
        return callback( this,... )
    end
end

function timer_mgr:new_timer( after,repeated,this,callback,... )
    local timer_id = self:next_id()
    self.timers[timer_id] = save_timer( this,callback,... )
end

function timer_mgr:do_timer( timer_id )
    local timer = self.timers[timer_id]

    -- 調用以前保存的定時器回調
    return timer()
end

而table要傳可變參則不太好處理了,須要另外建立一個table來pack參數,調用時再unpack,或者只用一個table把callback函數和參數存一塊兒,調用時把函數移除再unpack。總而言之,在這種須要保存參數的回調,closure更合適。固然,若是你的回調函數不帶參數,那就是另一碼事了。lua

  查了下,以前也有人作了相似的測試,結果也差很少:http://lua-users.org/wiki/ObjectOrientationClosureApproachspa

相關文章
相關標籤/搜索