ngx.thread.spawn和标准的coroutine.create创建出来的协程,到底有啥区别呢?

823 views
Skip to first unread message

小冶

unread,
May 14, 2014, 12:17:34 PM5/14/14
to open...@googlegroups.com
我试了一下,发现前者好像与当前请求共用一个ngx.ctx,后者则不是。
我有一个需求,场景可以近似为开房间聊天,客户端用websocket连上来后,通过redis互转消息(因为每个websocket只能在自己的request里收发)
现在希望第一个用户在创建房间后,在服务器跑一个后台逻辑,如聊天过滤,或者超时踢人之类。
我想把这个逻辑写成一个死循环函数跑在协程里,应该用ngx.thread.spawn跑还是普通的coroutine.create呢?
潜在的要求是:
1、虽然这个协程是第一个用户创建的,但是当第一个用户退出(websocket断开)后,它还应该正常在跑
2、需要有一个终结它的地方,即当房间里所有用户都退出后,是不是应该让它自己去检测这个条件然后退出循环?还有别的外部结束办法吗

Yichun Zhang (agentzh)

unread,
May 14, 2014, 2:58:57 PM5/14/14
to openresty
Hello!

2014-05-14 9:17 GMT-07:00 小冶:
> 我试了一下,发现前者好像与当前请求共用一个ngx.ctx,后者则不是。

后者也是。不是就是 bug 了。

> 我有一个需求,场景可以近似为开房间聊天,客户端用websocket连上来后,通过redis互转消息(因为每个websocket只能在自己的request里收发)
> 现在希望第一个用户在创建房间后,在服务器跑一个后台逻辑,如聊天过滤,或者超时踢人之类。

超时保护应该尽量直接使用 websocket 的超时设置,见

https://github.com/openresty/lua-resty-websocket#set_timeout

注意,无论是 croutine.create() 创建的常规的 Lua coroutine 还是由 ngx.thread.spawn
创建的“轻量级线程”,都是和创建它们的请求绑定的。如果你要创建和当前请求分离开的后台逻辑,应当使用 ngx.timer.at().
你可以参考 lua-resty-upstream-healthcheck 库的实现:

https://github.com/openresty/lua-resty-upstream-healthcheck#readme

关于 ngx.thread.spawn() 创建的“轻线程”的行为细节,可以参考其官方文档:

https://github.com/openresty/lua-nginx-module#ngxthreadspawn

简单地说,“轻线程”是自动往前不断(异步地)执行的,由 ngx_lua 的轻线程调度器自动调度,而不用你自己一次一次地 resume. 而
coroutine.create() 创建的常规协程并不会自动往前执行,而需要你自己通过 coroutine.resume()
同步地调用。关于后者的细节可以参见 Lua 5.1 官方手册中的对应章节:

http://www.lua.org/manual/5.1/manual.html#2.11

> 我想把这个逻辑写成一个死循环函数跑在协程里,应该用ngx.thread.spawn跑还是普通的coroutine.create呢?
> 潜在的要求是:
> 1、虽然这个协程是第一个用户创建的,但是当第一个用户退出(websocket断开)后,它还应该正常在跑
> 2、需要有一个终结它的地方,即当房间里所有用户都退出后,是不是应该让它自己去检测这个条件然后退出循环?还有别的外部结束办法吗
>

建议实现为延绵不绝的定时器(可以由 init_worker_by_lua 发起第一个 timer)。尽量不要让单个处理程序(包括 timer
回调)本身运行太久。还是参考上面提及的 lua-resty-upstream-healthcheck 库的实现。

Regards,
-agentzh

小冶

unread,
May 14, 2014, 9:50:14 PM5/14/14
to open...@googlegroups.com


在 2014年5月15日星期四UTC+8上午2时58分57秒,agentzh写道:
Hello!

2014-05-14 9:17 GMT-07:00 小冶:
> 我试了一下,发现前者好像与当前请求共用一个ngx.ctx,后者则不是。

后者也是。不是就是 bug 了。


再次试了,发现区别了:
 
ngx.ctx.test = 1
 --1、ngx.thread.spawn(function()
 --2、co_run(function()
     while true do
         print("normal", coroutine.running(), ngx.ctx.test)
         ngx.sleep(1)
     end
 end) 

用2创建的coroutine,控制完全不会返回到主协程,即使调了ngx.sleep挂起,但这个挂起似乎并不是yield回处理请求的协程。
用1创建的coroutine,控制是会返回主协程的,也就是后面的代码会继续跑,而新创建的协程也在跑,两者已经没有从属关系了。
前面提到2感觉似乎没有共享ngx.ctx,恰是因为后续代码没有跑,所以没有在ngx.ctx里读到应有的值而误认为的。

Reply all
Reply to author
Forward
0 new messages