免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: linux_c_py_php
打印 上一主题 下一主题

[其他] 【(LUA相关)一个支持yield的server能避免掉轮询检查coroutine状态的命运吗?】 [复制链接]

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
51 [报告]
发表于 2013-02-24 22:55 |只看该作者
本帖最后由 linux_c_py_php 于 2013-02-24 22:59 编辑
starwing83 发表于 2013-02-24 22:46
回复 42# linux_c_py_php


这个卡着是允许的, 是正常的, 对于那些该yield出去并且去epoll里跑异步的如果还卡着跑, 那就不对了.

我说的都是正常情况, 比如给lua提供个connect接口, 实际底层是注册给epoll后立马就yield了, 等connect事件完成会resume去跑剩下的lua逻辑, 当然剩下的lua逻辑又会有类似的接口, 如此resume->yield不停往复, 直到lua代码全部执行完. 但天知道你调用100次connect到底哪时候能把整个lua脚本跑完, 我的server是不知道的, 我只有coroutine的lua_State可以看status, 与此同时也许这个lua脚本里的第N次connect正在epoll里异步的执行着:

connect_100times.lua:

for i=1, 100 do
     succeed, connUserData = server:connect('localhost', 80) -- 底层是epoll下的非阻塞connect
     ...
     ...
     server:close(connUserData)
done

我的脚本就要这样跑, 第99次resume返回到非阻塞connect的event callback中时, 我并不打算在这里检查coroutine死了没有, 于是server对lua脚本执行结束毫不知情, 我就是要解决这个"毫不知情".

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
52 [报告]
发表于 2013-02-24 22:56 |只看该作者
回复 49# linux_c_py_php

coroutine当然不会“没完没了”,当你调用阻塞调用比如read/write,或者主动yield的时候它就返回了。
然后server才有机会再次调用epoll,等待下一个IO事件。
当事件发生后,server去resume coroutine

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
53 [报告]
发表于 2013-02-24 23:02 |只看该作者
回复 49# linux_c_py_php


    我大概知道你的误区在哪儿了。

对coroutine来说,无论这个请求是怎么被处理的,无论coroutine在哪儿等。在外界看来,这个coroutine都是“顺序执行”的,都是一个resume然后事情搞完了就返回。问题是,如果coroutine不返回怎么办?coroutine一个死循环怎么办?哦,那就完蛋了= =真的。

coroutine不配合就挂,这就是“协作式”的含义,你不协作,整个都会挂。

那么,对coroutine的执行怎么做呢?假设coroutine是“良好居民”,那么它执行的结果只有两个:要么就做完了退出,这时即使fd还有新的请求,coroutine也不会再继续了(或者你的框架重新启动coroutine);要么就是等待在另外的事件上,这时如果coroutine在线程里面,就继续处理下一个coroutine,如果跟epoll在一个线程,就继续epoll阻塞然后处理下个coroutine……总之你必须有个循环是不是 = =不然怎么叫事件循环

这样说是不是明白了?

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
54 [报告]
发表于 2013-02-24 23:05 |只看该作者
回复 51# linux_c_py_php


    ……………………你一次只能connect一次………………然后阻塞在这一个connect上………………

这个connect不完成,下一个connect请求根本就不会发生!!因为你的coroutine根本没执行到这个地方!根本就没有一个新的connect被调用!

结果就是,epoll处理第一个connect,第一个connect成功以后继续执行,继续执行直到第二个connect被调用,这时第一个connect已经被咔嚓掉了(因为处理完了),因为coroutine本身会被阻塞,所以处理肯定是串行的,绝对不是并行一次产生1000次注册的。

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
55 [报告]
发表于 2013-02-24 23:06 |只看该作者
本帖最后由 linux_c_py_php 于 2013-02-24 23:17 编辑
windoze 发表于 2013-02-24 22:56
回复 49# linux_c_py_php

coroutine当然不会“没完没了”,当你调用阻塞调用比如read/write,或者主动y ...
\

本来就是这样, 我没否认这个啊, 这个我肯定知道, 这些东西我已经掌握了...

但什么时候继续处理下一个请求?

如果是starwing87的coroutine脚本的思路, 那么其实就是server解析了request就放到一个队列里存着, 然后立马看一下当前coroutine是否yield在了wait上, 如果是就resume, 否则坐视不管(因为只可能是yield在move上了, 等下次lua被resume再次跑到wait肯定会检测到队列里的请求, 于是不会yield而是继续跑while内), 这一点我没理解错吧。

这个我理解, 相当于传统C开发里的线程池, 你的coroutine相当于一个业务线程永不退出.

我的做法相当于来一个连接创建一个线程, 干完一个短连接请求就挂掉线程.

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
56 [报告]
发表于 2013-02-24 23:08 |只看该作者
本帖最后由 linux_c_py_php 于 2013-02-24 23:10 编辑
starwing83 发表于 2013-02-24 23:05
回复 51# linux_c_py_php


是啊啊啊啊啊!!!!!!!!!!!!1

你们大爷的, 你们以为我低能?

这些lua和epoll交互我肯定懂, 草, 我当然知道100个connect是顺次发生的, 一次resume->yiled发生一次, 每次都会需要借助epoll做异步的连接事件.

我的意思是当整个lua脚本跑完了, server却不知道它跑完了, 这个连接挂住了, 除非有外力推动它说: 当前的请求已经跑完lua了, 你可以继续处理下一个了.


我的疑惑你们懂吗,我擦, 敢不敢不要用看新手的角度看问题, 这些JB玩意我肯定都懂.

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
57 [报告]
发表于 2013-02-24 23:13 |只看该作者
nginx/lighttpd的插件架构, 敢不敢拿这些东西来理解我的意思啊.

它们都支持你的插件可以yield出来, 它们是通过不断的轮询插件, 给插件cpu使用, 直到插件说它已经处理完了.

这和这里轮询coroutine是否完成有个JB区别啊, 有没有啊.

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
58 [报告]
发表于 2013-02-24 23:15 |只看该作者
starwing83 发表于 2013-02-24 22:44
要LF的话(我个人不是很理解这个),恐怕必须要多个lua_State了,因为LF似乎是可以完全并行执行的。Leader得到请求以后resume coroutine,每次得到数据都resume,直到自己再次成为leader。每个不同的线程一个独立的lua_State,在自己的一亩三分地玩蛋,恩~


你可以建立一个线程池,每个线程池都执行相同的过程,等待同一个epoll fd set,因为session只和fd关联,不和thread关联,所以随着IO事件被分配到不同的thread里,session也会调度到不同的thread上,当然,同一个session在不同的时刻也可能被调度到不同的thread上。

可以做一个类比,这个类似于单CPU和多CPU时OS调度thread/process的过程。

PS. 如果你做的够精细,你也可以实现session/thread的亲和性(affinity)策略(类比OS里Thread/process调度策略中的CPU Affinity),这在某些情况下可能是有用的,因为可能session中使用了某些外部函数,这些函数可能需要TLS支持(我在以前的项目里遇到过这个问题)。

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
59 [报告]
发表于 2013-02-24 23:15 |只看该作者
我不用lua一样实现可以yield的c server, 之前都开过一个帖子, 用lua对我来说觉得有用处的就是可以让小白写阻塞一路到底的代码, 但实际上是高效的异步处理.

如果让小白去给nginx开发个模块, 它能行吗, 所以不就有了nginx-lua吗, 但尼玛nginx-lua也是nginx module, 是要被nginx的插件机制不断轮询: "你搞定了没? 没搞定过会在来问题你", 这和coroutine自身的yield和resume没有半毛钱关系。

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
60 [报告]
发表于 2013-02-24 23:17 |只看该作者
回复 56# linux_c_py_php


    我告诉你无数次了 = =resume返回LUA_OK就是执行完了= =你要我说多少遍呢 = =

你是不是担心resume始终返回LUA_YIELD?这有两种情况:第一种情况是这个coroutine在某个事件上等待,这很容易判断的,这种情况下,这个事件肯定已经被注册了,只需要回到epoll即可(因为coroutine肯定没执行完),接下来是不是执行这个coroutine是不确定的,接下来执行的那个coroutine是什么是由“那个coroutine所关联的事件到了”决定的。

如果YIELD了但是没有在某个事件等待,你可以利用Lua的垃圾回收机制:这个coroutine一定没有被保存在某个地方,几次循环以后就会被喀嚓掉。甚至因为没有向epoll注册fd,而导致epoll没有fd了从而退出。这是没有问题的,其实就是一个永远没有机会被resume的coroutine被垃圾回收,不影响你的框架。

如果这个coroutine返回,证明coroutine请求完了当前请求所有的事件,这时候相当于服务器已经给了客户端所有需要的数据了,想象一下http服务器面对这种情况下是怎样的,直接断fd然后回收掉这个coroutine。

就这三种情况,还能怎么样呢= =
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP