Chinaunix
标题:
写了个lua+多线程+libevent的东西,求意见
[打印本页]
作者:
fakepersona
时间:
2014-01-08 19:56
标题:
写了个lua+多线程+libevent的东西,求意见
地址:
https://github.com/ackroyd-xt/lua_libevent_multiThread_server
最近学lua和libevent,然后看了两个写了server的帖子
http://bbs.chinaunix.net/thread-3776236-1-1.html
还有一个忘了地址了,是写了个lua+libevent 的单线程server (说是多线程但只是coroutine,实际上只是单线程)
于是跟风写了个自己的。。但是有些疑问,希望能解答。。
不经常上chinaunix,希望能直接发到邮箱谢谢。。
基本想法是:
1. 线程池 (之前自己写过一个,主线程负责任务分配,子线程接收任务,没有任务就使用 pthread_cond_wait阻塞等待任务
2. 主线程应用libevent负责epoll,任何连接有事件了就组装一个任务分发给空闲线程 (实际上只是分发一个描述符下去)
3. 每个描述符对应一个lua_State,由lua保存这个连接的状态(之前用lua_newthread但是多线程操作会coredump)
4. 子线程接到任务后resume 对应的lua_State, lua跑脚本,跑到yield处 返回到子线程,子线程认为任务完成陷入pthread_cond_wait
5. lua_state在程序启动时建立,只有在出错时才删除重建。当连接正常断开时lua脚本回到开头的位置继续接受请求,避免多次申请lua_state
6. lua在yield之前设置标识,子线程在lua yield返回后根据标识向主线程申请注册对应的事件(通过管道完成,向管道写一个fd,主线程检查全局数组conn的下标为fd的元素,根据该元素的标识注册对应的事件)。(之前是子线程直接注册事件,但是libevent好像没有多线程所以core掉了,现在是全部交给主线程来注册)
想到的优点:
1. 因为是多线程,所以和单线程的实现相比,就算服务端阻塞也没问题(例如数据库查询)(也就是增加了吞吐量?)
2. 因为用了lua,服务端逻辑可以写的比较复杂(和客户端的交互可以有很多次,可以加上超时之类的东西,而且都是非阻塞的;可以把 读写的注册和yield包装起来,这样lua脚本可以写的像阻塞的但实际都是非阻塞的) 。 如果是简单的多线程实现,就是一个连接占用一个线程,无法应付少量活跃连接、大量不活跃连接的情况; 而这个实现由于有coroutine且本身有多线程,实际需要的线程数量=实际活跃的连接数,所以可以支撑更多的连接(吞吐量
性能上,在具体场景可能略低于更有针对性的实现(例如简单服务器场景的单线程libevent实现, 复杂服务器场景的 简单多线程实现)。个人觉得就是个适用性较广、性能还不差的一个东西。
目前的缺点和问题:
1. 为了支持复杂的客户端和服务端交互的逻辑(而且要非阻塞),server业务逻辑必须用lua写,或者用 C写但是要用continue-program-style (试过一个例子,就是每次yield时注册下次调用的continue函数,感觉写起来比较麻烦)。如果用lua写,可能就需要很厚的胶水层(稍微复杂点的东西都要放到C里包装起来给到lua调用) ----------这个感觉是最大的问题,不管写什么都要用lua包装下,虽然可以直接用C写但 cps风格很麻烦,每次yield之后的操作都要放到下一个函数里实现。想写个包装的东西把yield和continue函数包装起来,但没想到什么办法
2. 个人感觉 性能+实现复杂度 比不上更具有针对性的、更简单的实现,不管怎么写感觉还是比不过libevent。 相比简单多线程的实现,例如要查询数据库的场景,简单多线程是把线程切换(等待客户端回复等阻塞socket操作导致线程阻塞)的工作交给cpu,这个实现是自己实现了这部分工作换来更大吞吐量,但是这个感觉意义不大。。。
征求意见,1. 怎么让胶水层不那么厚,至少不要每次写server都要手动加厚胶水层 2. 怎么进一步提升性能,在服务较简单以至于可以直接使用单线程libevent实现、服务端操作不会阻塞的情况下,有无让性能超过单线程libevent的可能? 或者涉及数据库操作时,相比直接使用简单多线程实现, 性能相比又怎样?
作者:
群雄逐鹿中原
时间:
2014-01-08 21:51
本帖最后由 群雄逐鹿中原 于 2014-01-08 21:54 编辑
建议参考下luvit。
如果把 udt 加上和 luajit 加上,就完美了。
作者:
linux_c_py_php
时间:
2014-01-09 09:51
楼主的思路和当年的我一样有问题,对coroutine实践还是缺乏点经验,可以看看我当时的学习成果的设计思路。
http://bbs.chinaunix.net/thread-4076795-1-1.html
作者:
zylthinking
时间:
2014-01-09 10:28
因为用了lua,服务端逻辑可以写的比较复杂
这是什么意思, 难道不用 lua 就不能写的比较复杂?
作者:
fakepersona
时间:
2014-01-09 18:26
回复
3#
linux_c_py_php
好像之前看的单线程lua server就是你这个?但是好像是在另一个帖子。。。我之前确实有看过一个lua_frame的东西,好像就是你这个
但是你的实际上是单线程(coroutine的线程而非真实线程),我的是多线程的实现。
但是你的帖子和回复里都没看到有说问题在哪里,能直接明说吗?谢谢~
作者:
fakepersona
时间:
2014-01-09 18:35
回复
4#
zylthinking
只是说用lua很方便。例如 客户端发报文---服务端校验并回复---客户端发报文---服务端进行数据库处理并回复 这种交互,如果不使用lua的话,我能想到的是:
1. 写成多线程的,每个线程处理一个请求(或者常驻线程轮流处理请求),但这样就不是非阻塞的,线程会被阻塞的连接占用
2. 写成多线程的,每个线程轮流处理请求,并向主线程申请注册libevent事件然后等待(但这样这个线程仍被该连接占用)
3. 写成单线程的,每一个交互步骤都要写一个callback,在执行完一个callback后再注册下一个callback,这种方式写起来会很麻烦;而且如果还要加上更多的if -else分支的话就很麻烦了。其实就是把lua的栈管理由人工来做了
作者:
yulihua49
时间:
2014-01-27 16:46
本帖最后由 yulihua49 于 2014-01-27 16:48 编辑
fakepersona 发表于 2014-01-09 18:35
回复 4# zylthinking
4.linux_c_py_php的方法就很好。用epoll内置的L/F模型。具体做法可以改进。
直接用epoll何必要linevent?
作者:
fakepersona
时间:
2014-02-10 15:50
回复
7#
yulihua49
用的AIX没有epoll。。
欢迎光临 Chinaunix (http://bbs.chinaunix.net/)
Powered by Discuz! X3.2