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

相关文章
相关标签/搜索