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 = 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的更多相关文章
- Lua中的closure(闭合函数)
词法域:若将一个函数写在另一个函数之内,那么这个位于内部的函数便可以访问外部函数中的局部变量,这项特征称之为“词法域”. 例:假设有一个学生姓名的列表和一个对应于没个姓名的年级列表,需要根据每个学生的 ...
- lua table integer index 特性
table.maxn (table) Returns the largest positive numerical index of the given table, or zero if the t ...
- 树形打印lua table表
为方便调试lua程序,往往想以树的形式打印出一个table,以观其表内数据.以下罗列了三种种关于树形打印lua table的方法;法一 local print = print local tconca ...
- lua table 排序--满足多条件排序
前提 假设 一个小怪 有三种属性,等级(level).品质(quality).id(pid) 我们需要对他们进行排序,两种排序情况,第一是单一属性排序,比如按照等级进行排序,或者多种属性进行优先级排序 ...
- cocos2d-x lua table数据存储
cocos2d-x lua table数据存储 version: cocos2d-x 3.6 1. 将table转为json http://blog.csdn.net/songcf_faith/art ...
- cocos2d-x lua table与json的转换
cocos2d-x lua table与json的转换 version: cocos2d-x 3.6 1.引入json库 require("src/cocos/cocos2d/json&qu ...
- Lua table使用
days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Th ...
- lua table表
lua table表 语法结构 创建一个 table 直接使用 "{}" 即可 table1 = {} -- 赋值 table1["name"] = " ...
- lua table表判断是否为空
官方手册里早已经给了答案,那就是靠lua内置的next函数 即如此用: a = {} if next(a) == nil then next其实就是pairs遍历table时用来取下一个内容的函数. ...
随机推荐
- 依赖管理系统 go modules
golang在1.11版本中引入了新的包管理工具 go mod 类似于maven包管理(多项目公用),而之前的vendor类似于node的node_modules管理(各个项目一份) 依赖信息添加到g ...
- WebsSocket
本篇阅读目录 一.Websocket原理(握手.解密.加密) 二.基于Python实现简单示例 回到顶部 一.Websocket原理(握手.解密.加密) WebSocket协议是基于TCP的一种新的协 ...
- OpenGL学习(4)——纹理(补)
完成章节后练习 练习 1. Make sure only the happy face looks in the other/reverse direction by changing the fra ...
- 微信demo小游戏:飞机大战从无到有
微信demo游戏飞机大战从无到有 现在创建新项目会默认给飞机大战的demo,这里给大家从基础开始讲解游戏的从无到有是怎么实现的. 具体实现步骤: 创建背景图->背景图运动起来->创建飞机并 ...
- Unit Testing, Integration Testing and Functional Testing
转载自:https://codeutopia.net/blog/2015/04/11/what-are-unit-testing-integration-testing-and-functional- ...
- C语言I博客作业12—学期总结
一.我学到的内容 二.我的收获(包括我完成的所有作业的链接+收获)不能只有作业链接,没有收获 作业次数 作业链接 第一次 C语言I博客作业01 第二次 C语言I博客作业02 第三次 C语言I博客作业0 ...
- TP5.1框架中的模型关联
一对一关联 hasOne('关联模型','外键','主键'); 关联模型(必须):关联的模型名或者类名 外键:默认的外键规则是当前模型名(不含命名空间,下同)+_id ,例如user_id 主键:当前 ...
- Thinking In Java 4th Chap5 初始化和清理
类的构造器名必须与类名一致,且无返回类型,通过参数类型的不同(即使顺序不同也行)可以重载构造器,也可以以此技巧重载方法 this关键字:表示对“调用方法的那个对象的引用”,也可将当前对象传递给其他方法 ...
- 20190806-Python基础 第二章 列表和元组(3)元组&章小结
元组,不可修改的序列(与列表的唯一差别) 1. 元组用圆括号括起,用逗号分隔 2. 如果只有一个值,也必须在后面加上逗号 print((42)) print((42,)) 结果: 42 (42,) p ...
- scrapy 框架持久化存储的三个方法 存入 mysql 文件 redis
这里就不做详细讲解了 毕竟不是一句两句能说的清楚,所以我把代码和注释放到了这里 谢谢! import pymysql from redis import Redis # 写入mysql class W ...