回调还是消息队列
前几天在做 Hive 的 socket 库的时候, 遇到一个问题很典型,我记得不是第一次遇到了。值得记录一下。
socket 底层有一个 poll 的 api ,通过 epoll 或 kqueue 或 select 取得一系列的事件。用 lua 怎么封装它呢?
一个比较直接的想法是注入一个 callback function ,对于每个事件回调一个 lua 函数。但这容易引起许多复杂的问题。因为回调函数很不可控,内部可能抛出异常,也可能引起函数重入,或是做了一些你不喜欢去做的事情。
如果面面俱到,就会让原本 C/Lua 边界的性能问题更加恶化。
所以,我采用了方案二:把所有事件以及相关数据全部返回,让后续的 Lua 代码去处理 C 层获取的所有事件。
这个方案也容易造成性能问题,那就是临时构件复杂数据结构,对 Lua VM 的 GC 造成的压力。
为了优化这点,我主张从外部传入一个接收结构的 table ,也就是一个空的消息队列。
然后在 C 层使用 rawseti 把消息加进去。rawseti 是一个相当高效的 lua api 。因为 lua table 如果只有顺序的整数做 key 的话,性能和 C 数组无异。
因为每条消息上有不只一个数据,所以最终的数据结构是一个二维数组。为了不每次临时创建大量的 table ,可以缓存用过的 table 到另一个 table 中。
比如,上次收到 4 条消息,这次收到 5 条的话,就新创建一个 table 保存第 5 条消息关联的参数。下次又收到三条消息的话,就把过剩的两个 table 转移到 cache 中备用。当系统稳定运行后,相当于创建好了整个二维数组接收 C 层产生的数据,而不会临时构建 lua 表了。
再说一个不那么相关的话题:Lua 下实现一个简单的消息队列,我觉得如下简单的几条代码就可以了。
local q1 = {} local q2 = {} -- 产生消息只需要 table.insert(q1, msg) -- 分发消息需要两层循环, 可以处理 dispatch 过程中产生的新消息 while q1[1] do q1,q2 = q2,q1 for i=1,#q2 do dispatch(q2[i]) q2[i] = nil end end
建议继续学习:
- Redis消息队列的若干实现方式 (阅读:10740)
- 各消息队列软件产品大比拼 (阅读:5176)
- 使用django+celery+RabbitMQ实现异步执行 (阅读:5045)
- 终于把搜索更新改成基于MQ(Message Queue, 消息队列)的方式了 (阅读:3470)
- 在回调和闭包中的内存泄漏 (阅读:3070)
- State Threads 回调终结者 (阅读:1764)
- HQueue:基于HBase的消息队列 (阅读:1664)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:云风的 BLOG 来源: 云风的 BLOG
- 标签: 回调 消息队列
- 发布时间:2013-07-07 17:55:03
- [2528] 代理的加密部分
- [1329] 创业笔记 | 从0到1开公司是什么体验
- [649] vimgtd-在vim(gvim)中实现GT
- [574] 查找第K小的元素
- [73] Oracle MTS模式下 进程地址与会话信
- [65] Go Reflect 性能
- [64] 【社会化设计】自我(self)部分――欢迎区
- [64] 如何拿下简短的域名
- [63] 图书馆的世界纪录
- [61] android 开发入门