最近在重构自己写的框架中的定时器模块,需要把回调函数保存起来,大概如下:

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 = local table_mgr = {}
local closure_mgr = {} function test_table() local beg_m = collectgarbage("count")
local beg_tm = os.clock() for idx = ,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 = ,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在这个应用场景下就优雅得多,因为可以很方便地传更多的参数,比如:

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更合适。当然,如果你的回调函数不带参数,那就是另外一码事了。

  查了下,之前也有人做了类似的测试,结果也差不多:http://lua-users.org/wiki/ObjectOrientationClosureApproach

lua table vs closure的更多相关文章

  1. Lua中的closure(闭合函数)

    词法域:若将一个函数写在另一个函数之内,那么这个位于内部的函数便可以访问外部函数中的局部变量,这项特征称之为“词法域”. 例:假设有一个学生姓名的列表和一个对应于没个姓名的年级列表,需要根据每个学生的 ...

  2. lua table integer index 特性

    table.maxn (table) Returns the largest positive numerical index of the given table, or zero if the t ...

  3. 树形打印lua table表

    为方便调试lua程序,往往想以树的形式打印出一个table,以观其表内数据.以下罗列了三种种关于树形打印lua table的方法;法一 local print = print local tconca ...

  4. lua table 排序--满足多条件排序

    前提 假设 一个小怪 有三种属性,等级(level).品质(quality).id(pid) 我们需要对他们进行排序,两种排序情况,第一是单一属性排序,比如按照等级进行排序,或者多种属性进行优先级排序 ...

  5. cocos2d-x lua table数据存储

    cocos2d-x lua table数据存储 version: cocos2d-x 3.6 1. 将table转为json http://blog.csdn.net/songcf_faith/art ...

  6. cocos2d-x lua table与json的转换

    cocos2d-x lua table与json的转换 version: cocos2d-x 3.6 1.引入json库 require("src/cocos/cocos2d/json&qu ...

  7. Lua table使用

    days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Th ...

  8. lua table表

    lua table表 语法结构 创建一个 table 直接使用 "{}" 即可 table1 = {} -- 赋值 table1["name"] = " ...

  9. lua table表判断是否为空

    官方手册里早已经给了答案,那就是靠lua内置的next函数 即如此用: a = {} if next(a) == nil then next其实就是pairs遍历table时用来取下一个内容的函数. ...

随机推荐

  1. osg(openscenegraph).chm帮助文档

    openscenegraph 3.6.3 链接:https://pan.baidu.com/s/1cQkiTPQx5MIIfxe5FTfjYw 提取码:7w4z openscenegraph  3.4 ...

  2. pyCharm最新2017激活

    pyCharm最新2017:下载地址 下载完成后安装软件 启动pyCharm,进入下面窗口 选择License server 在 server选项里边输入 http://elporfirio.com: ...

  3. 实现两个DataTable的联合查询

    如方法一描述:将子表的数组追加到主表数组的下面.从而实现类似于视图(单表)的效果. 那么Left Join(Inner Join)和Right Join(Outer Join) 将如何实现呢? 明天仔 ...

  4. mysqlslap 性能测试

    --create-schema=name 指定测试的数据库名,默认是mysqlslap --engine=name 创建测试表所使用的存储引擎,可指定多个 --concurrency=N 模拟N个客户 ...

  5. edusoho twig 引入文件功能

    在这里不得不提 edusoho twig 模板引擎了 跟smarty 比较类似 不过感觉还是更好一点儿 这里用的标签就只有一个 {% include '路径/文件名' %} 大家在首页做的改动比较多 ...

  6. 最新 顺网科技java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.顺网科技得等10家互联网公司的校招Offer,因为某些自身原因最终选择了顺网科技.6.7月主要是做系统复习.项目复盘.Lee ...

  7. HADR和TSA需要注意的问题

    1.必须将主备数据库都执行一次完全备份,然后使用主库执行online备份后同步至备库: 2.同一台服务器只能添加一个TSA集群管理器,此服务器中无论有几个实例和几个数据库,都会被添加至首次创建的集群中 ...

  8. 用命令将本地项目上传到git

    1.(先进入项目文件夹)通过命令 git init 把这个目录变成git可以管理的仓库 git init 2.把文件添加到版本库中,使用命令 git add .添加到暂存区里面去,不要忘记后面的小数点 ...

  9. 超级简单的requests模块教程

    在web后台开发过程中,会遇到需要向第三方发送http请求的场景,python中的requests库可以很好的满足这一要求,这里简要记录一下requests模块的使用! 说明: 这里主要记录一下req ...

  10. Python 第一节随堂练习

    作业: 1 从键盘输入一个整数,判断该数字能否被2和3同时整除,能否被2整除,能否被3整除,不能被2和3整除,输出相应信息 1 my_num = int(input('请输入一个整数')) 2 if ...