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