最近在重构本身写的框架中的定时器模块,须要把回调函数保存起来,大概以下:数据结构
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