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时用来取下一个内容的函数. ...
随机推荐
- tomcat 8.xxx ssl使用websocket Failed to close the ServletOutputStream connection cleanly
报错: 2019-09-17 10:30:17.277 default [https-jsse-nio-8110-exec-20] INFO o.a.t.w.s.WsRemoteEndpointImp ...
- React Native使用code-push实现热更新
这里就不记录了,下面的传送门介绍的通俗易懂,很详细,一步一步很容易实现成功. http://www.jianshu.com/p/f8689ccf0007
- swift 第十二课 as 的使用方法
忽略的基础性的问题,应该早点写出这个问题的解释比较好,毕竟 swift 好多的地方都用到了 as as!as?,是非常容易搞晕大脑的 1,as使用场合 (1)从派生类转换为基类,向上 ...
- 使用mybatis的resultMap进行复杂查询
记录下mybatis的集合查询中碰到的问题 https://jaychang.iteye.com/blog/2357143 MyBatis ofType和javaType区别 https: ...
- 10-3 LVM(逻辑卷管理器)
LVM(逻辑卷管理器) 允许对卷进行方便操作的抽象层,包括重新设定文件系统的大小 允许在多个物理设备间重新组织文件系统 将设备指定为物理卷 用一个或者多个物理卷来创建一个卷组 物理卷是用固定大小的物理 ...
- HelloCube:IJobForEach
此示例演示了基于作业的ECS系统,该系统可旋转一对立方体. 它显示了什么? 此示例基于ForEach示例构建,并说明如何在多线程作业中执行相同的工作,而不是在主线程上执行相同的工作. 与前面的示例一样 ...
- java 分布式实践
java 分布式实践 spring boot cloud实践 开源的全链路跟踪很多,比如 Spring Cloud Sleuth + Zipkin,国内有美团的 CAT 等等. 其目的就是当一个请求经 ...
- sql注入01
1.SLQ:操作数据 数据库结构 create/drop database create/alter/drop table 数据库内容 insert values语句 insert into tabl ...
- spring使用FactoryBean给ioc容器加入组件
FactoryBean是srping的一个接口,现在我们来创建一个类MyFactoryBean 来实现FactoryBean接口 package org.springframework.beans.f ...
- Collection集合常用的功能
package demo06; import java.util.ArrayList;import java.util.Collection; /** java.util接口 Collection&l ...