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时用来取下一个内容的函数. ...
随机推荐
- 07Flutter ListView基础列表组件、水平列表组件、图标组件
ListView: ListView:参数 scrollDirection:Axis.horizontal:水平列表.Axis.vertical垂直列表 padding:内边距 ...
- centos7用yum安装node.js v8.x
1.更新node.js v8.x yum源 // 不更新,提示没有 packages文件 # curl --silent --location https://rpm.nodesource.com/s ...
- MSMQ菜鸟教程
一 .MSMQ概述 MSMQ全称MicroSoft Message Queue,微软消息队列,是在多个不同的应用之间实现相互通信的一种异步传输模式,相互通信的应用可以分布于同一台机器上,也可以分布于 ...
- RabbitMQ简单Java示例——生产者和消费者
添加Maven依赖: 使用rabbitmq-client的最新Maven坐标: <!-- https://mvnrepository.com/artifact/com.rabbitmq/amqp ...
- Reset Password 重置密码 (CentOS 5,6,7 ; Juniper Networks: SRX100 )
一些重置root 密码的文档分享(来自官网): CentOS 5,6,7 Juniper Networks : SRX100 链接:https://share.weiyun.com/5BM4kwK ...
- 【ABAP系列】SAP ABAP Break Point
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP Break P ...
- souce and bash 的区别
对于一些环境变量的配置文件,如想使更改后立即生效,多用 souce +file 执行后即可.如/etc/profile 里加了配置, source 和 bash 的区别: source filena ...
- 前端面试经典题之ES6新特性
ES6 主要是为了解决 ES5 的先天不足,在原先ES5的基础上新增了许多内容,本篇文章将列举出ES6中新增的10大特性. 一. let 和 const 与var不同,let和const都是用于命名局 ...
- Windows系统Python直接调用C++ DLL
环境:Window 10,VS 2019, Python 2.7.12, 64bit 1,打开 VS 2019,新建C++ Windows 动态链接库工程 Example,加入下列文件,如果Pytho ...
- 最新 小米java校招面经 (含整理过的面试题大全)
从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.小米等10家互联网公司的校招Offer,因为某些自身原因最终选择了小米.6.7月主要是做系统复习.项目复盘.LeetCode ...