前两天春哥回复说,正在计划加入ngx.mutex接口,来支持协程的挂起和唤醒,而且是要支持跨上下文的。
我大略看了一下当前ngx.sleep的代码,感觉可以通过添加两个简单的函数,来达成一种更简单的协程挂起和唤醒的支持。
返回一个跟当前coroutine相关的一个类似句柄的对象,多次调用也仅仅返回一份,其内部维护着corouine状态、切换上下文等相关信息,但对lua层不可见。
ngx.wakeup( thread_handler, ... )
thread_handler是之前this_thread调用的返回值。
如果thread_handler相关的那个coroutine没有处于sleep状态,或者已经结束退出了,或者已经被销毁了,此函数都不起作用。
仅当该coroutine处于sleep状态中时,会被wakeup调用唤醒,且sleep函数返回wakeup传入的参数
这个设计需要对sleep函数添加一些额外的功能(或者可以考虑引入一个新函数):
1. 支持无限时间的睡眠,比如传-1或nil做入参。
2. 支持返回值,可以返回在wakeup调用时传入的参数,程序可以通过此特性判断是sleep超时返回还是被wakeup唤醒。
3. 其它情况下,行为与原sleep完全一致,这样不会影响旧的代码。
更复杂的同步行为,比如mutex和semphore,都可以依赖此特性由纯lua代码实现。
最终的实际代码可能会是这样:
global_var.thread_handler = ngx.this_thread()
local result = ngx.sleep( -1 )
if result == true then
...
thread_handler保存后,在另一个协程里调用:
ngx.wakeup( global_var.thread_handler, true )
设计的理由:
没有细看过openresty代码,但似乎目前通过content_by_lua*处理请求的所有coroutine处于调度模块的监控之下。
有个集中的调度器监管这些coroutine的上下文,并负责在请求超时后,对上下文相关资源进行回收,从而避免处理不当造成的泄漏问题。
我想这也导致了跨越上下文的种种限制,包括做mutex的设计时需要更多复杂情况的考量。
这样设计,通过引入一个与coroutine生命期弱相关的thread_handler,将生命期管理逻辑与唤醒逻辑完全隔离,可以用尽可能小的改动实现功能支持,尽可能不影响现有系统。
实现时,需要cancel掉当前负责睡眠的计时器,不知道在c层面这个cancel timer的接口是否已经存在,如果已经有了,感觉实现上述两个接口及sleep的改进应该并不需要太多代码。
最后,其实我还没有细读过nginx和openresty的源码,最近也不太可能有时间。如果由于我的理解浅显给出了错误的建议,实在是无心之失,见谅。
由于没有细读过源码的缘故,我也不敢造次直接自己做。上述建议基于我之前自己实现C语言协程库的经验,其中逻辑应该有很多相似之处。
如有不妥之处,希望大家共同探讨,原谅我作为外行而指手画脚之嫌,谢谢!