2014-06-07 7:56 GMT-07:00 小冶:
>
> 问题是sleep是马上把自己卡住,而且其“唤醒”机制是“强制粗暴”的,即:时间到了就resume,没有任何逻辑控制的余地。
你为什么不能在这里直接创建一个轻量级线程来执行循环 sleep?
> 而我需要的是“在10秒后执行一个检测:如果当前co卡住了,那么resume它,否则,什么也不做”
> 目前整个操作流程是:
> 1.在websocket里while(1)处理客户端的多个请求
> 2.在某个请求里,create一个co,这个co随着每次请求,都resume往前跑一点,然后yield等下一个请求输入
> 3.然而有一种输入是可有可无的,如果10秒内客户端还没有给出,那么自动生成一个默认的输入
> 4.所以针对那种情况,希望在yield前,创建一个timer,在10秒后运行,检查该co是否还卡在当前等待点,如果是就直接resume它
>
其实标准的 coroutine API
本身的用处很有限。难道你要在这里自己进行时间片调度?我不清楚你这里的具体动机是什么,因为这种设计本身是低效的。建议针对你的业务逻辑重新设计具体的实现方式。
此处我对coroutine的使用是取代有限状态机,一般语言里实现状态机,都是一种输入对应一个函数,两次输入就是两次函数调用,如果其间要传递数据,只能存在状态机上成为“全局变量”,因此有大量的状态控制变量非常繁琐。但是在lua里可以用coroutine,将整个状态机的流程写成一个函数,当需要输入时yield,外部给予输入时resume,两次输入调用间所有局部变量、控制结构都在,非常方便。
类似的应用比如:多人打牌、回合制战斗,都是每人轮流输入以控制一个状态机运转,每次输入都要读秒超时保护,我用coroutine来表示之,在客户端实现得很好。逻辑代码是两端共享,但是因为nginx timer的限制,在服务端跑起来就不太顺。
> 另外还想再咨询下春哥,我的应用其实是基于长连接、而且连接之间有大量交互的
> 与nginx用于高并发短连接、各自独立少交互的本意并不符合,所以用起来很多时候都觉得有点束手束脚,一些简单的问题都想很多办法绕着走
你在哪里看到 nginx 只适用于高并发短连接?nginx 核心很早之前就已经内建了连接池的支持了。
虽然有连接池,但连接之间交互的方法,还是不太多?比如现在只能靠发消息,让每个连接自己处理,相当被动,而没有主动的跨连接操作
比如说,我要实现一个顶号(重复登录)检测功能,当用户在A设备上已经登录了,又在B设备上登录,需要把A上的连接关闭,
但现在我不能直接在B里找到连接A把它关掉了,只能给A发消息,让它自己close。
顺带说下我的实现细节,本来每个连接建立后,会在while里监听socket和db list(以userid为key)两个消息源
socket本身与用户端是一对一的只有自己能收发
db list用来处理与服务端其它连接的通信,以userid为key是很自然的(不然别人怎么定位它)
但是在顶号个例子中,A和B连接用的就是同一个userid,如果B给A发一个退出指令,结果会是它自己先收到。
于是只好给每个连接增加第3个消息源,key做到每连接不同,专门用于收发针对连接(而非用户)的消息。
这就马上又涉及下面的问题了:现在没有办法以epoll的形式同时等待多个事件源。
> 不知道openresty有无这方面的经典应用案例?未来的开发方向,是否加强这方面的功能?
> 比如之前呼声很高的cosocket双工问题(能跨ctx使用),过去好几个月了,还没有加进来,
我能理解全双工 cosocket
的重要性,但我作为一个有全职工作的有老婆孩子的普通人类,时间和精力都是有限的。我只能按照给我付薪水的公司的需求来安排工作的优先级。希望你也能理解这一点。
非常理解,以前也做过引擎支撑其它项目,对很多非正式需求都是有心无力。这里还是非常感谢春哥为我们提供了一个这么好的开源软件!
不过春哥如果有空可以写一些设计文档和关键代码模块解释,方便其它人理解,自己动手补全。
> 导致现在要想同时等待socket和redis消息,只能一个放短timeout另一个完全无阻塞式的轮询,十分别扭,而且即使开单进程模式,两个socket之间要互转数据都不能直接操作。
>
单 worker 进程模式在多核机器上没有什么实用意义。同时等待 websocket 和 redis 消息现在完全可以通过
ngx.thread.spawn 创建轻线程来实现。数据互转也有 Lua 模块级别数据、共享内存字典,或者 redis
这样的外部数据服务这三种不同共享粒度的方式。
这个问题之前讨论过多次,但是一直没说清楚:
你说的用ngx.thread.spawn创建coroutine,是可以实现多个事件源同时等待
但问题是每个coroutine管一个源,互相之间不能读写啊
我在db的coroutine里收到消息,处理结果要往socket上发,还是发不了,这个才是关键
因此我只能在同一个coroutine里用while去轮询各个源,而这个coroutine还只能是处理websocket请求的“主coroutine"
因为db只要通过不同的连接还能做到多ctx访问,但websocket就只有它自己那个请求ctx能用
只有实现socket双工了,在spawn出来的db coroutine里也能写,所谓”同时等待“才有意义。