IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

回调还是消息队列

云风的 BLOG 2013-07-07 17:55:03 累计浏览 3,896 次
本机暂存

   前几天在做 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

同分类推荐文章

  1. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. 推荐一些socket工具,TCP、UDP调试、抓包工具 (累计阅读 10,844)
  2. 推荐一些socket工具,TCP、UDP调试、抓包工具 (累计阅读 8,840)
  3. 流量低峰也烦人-lighttpd耗时长问题追查 (累计阅读 6,787)
  4. 浅析linux kernel network之socket创建 (累计阅读 6,739)
  5. python中的socket代理 (累计阅读 6,344)
  6. gen_tcp发送缓冲区以及水位线问题分析 (累计阅读 6,062)
  7. Nginx与Lua (累计阅读 5,669)
  8. netstat和web主机socket文件分析 (累计阅读 5,539)
  9. Nginx源码分析-Epoll模块 (累计阅读 5,102)
  10. Lua GC 的源码剖析 (2) (累计阅读 5,077)