lua+libuv的一些开发心得
Posted bywayboy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了lua+libuv的一些开发心得相关的知识,希望对你有一定的参考价值。
不断的查阅资料, 不断的学习, 阅读 lua代码. 一个人做开发其实是一个痛苦的过程,非常考验毅力和耐心。不过好在经过几个月晚上的学习积累, 已经渐入佳境。觉得有必要做一下笔记了。下面记录下踩过的一些坑。
第一个坑
原计划将sqlite数据库封装完全异步化的, 实现思路, 使用 uv_queue_work + 队列 来实现异步的数据库操作, 以达到利用一个独立线程来操作数据库的目的。 起初 我觉得通过 lua_newthread 创建一个线程, 然后在这个线程不和 的父线程又任何交集的情况下,应该会是线程安全的. 虽然没有把握,但是还是去阅读一下代码比较稳妥。 通过阅读 lua_pushlstring函数发现, 它会将长度少于40字节的字符串哈希后,并且只存保存一份。 这里用到了一个全局状态机来管理这些短字符串, 好吧 lua_newthread 并不是线程安全的. 而采用序列化的方法在lua线程之间交换数据, 对小数据包还好,但数据库的话可能一次查询大量数据, 序列化和反序列化的开销会非常可观,这一块暂时放弃. 后续有空再寻找其它方案。
第二个坑
libuv 的uv_async_send 和回调的执行并不是严格一对一关系, 多个连续的uv_async_send 只会触发一次 回调, 解决办法是 使用一个队列保存uv_async_send 的数据, 然后在回调里面遍历取出所有node 去操作.
关于协程化.
尽管lua并没有实现对称式协程, 但借助libuv,我们完全可以做出对称式协程的效果。 但我们进行一个异步IO操作的时候,挂起当前协程, 并让这个libuv对象持有它, 在 libuv回调的时候去恢复它即可. 我们设计的时候要遵循以下几条规则.
- uv_run 必须运行在主线程, 因为我们在事件回调的时候 lua_resume 的from 统一指定为 mainthread.
- 任何通过io操作挂起的协程只能被libuv的对应的io回调来恢复。
- tcp连接 的收到数据回调触发后要立即调用 uv_read_stop 来停止获取数据到达事件. 避免resume 栈错乱.
- 定时器封装的时候, 指定一个回调函数, 每次回调中使用 lua_newthread创建一个协程去执行该函数, 避免 重复resume协程.
- 借助 uv_async_send 来,实现了一个类似go语言的channel对象.
- UDP由于没有连接, 因此 需要为每一个数据包到达去创建一个协程. 类似 定时器的处理方法.
暂时写这么多。
以上是关于lua+libuv的一些开发心得的主要内容,如果未能解决你的问题,请参考以下文章