Skip to Content

start motan

Posted on One min read

ngx.thread.spawn与coroutine.create的区别

来源:OpenResty Google Groups

原文地址:https://groups.google.com/forum/#!msg/openresty/6NyxBC9R2UY/zycvr9TMCjIJ

本文来自于对谷歌邮件组网友提问的整理。

问题描述

我试了一下,发现前者好像与当前请求共用一个ngx.ctx,后者则不是。

我有一个需求,场景可以近似为开房间聊天,客户端用websocket连上来后,通过redis互转消息(因为每个websocket只能在自己的request里收发)

现在希望第一个用户在创建房间后,在服务器跑一个后台逻辑,如聊天过滤,或者超时踢人之类。我想把这个逻辑写成一个死循环函数跑在协程里,应该用ngx.thread.spawn跑还是普通的coroutine.create呢?

潜在的要求是:

1、虽然这个协程是第一个用户创建的,但是当第一个用户退出(websocket断开)后,它还应该正常在跑

2、需要有一个终结它的地方,即当房间里所有用户都退出后,是不是应该让它自己去检测这个条件然后退出循环?还有别的外部结束办法吗

春哥解答

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 库的实现。

经典Tips

无论是 croutine.create() 创建的常规的 Lua coroutine 还是由 ngx.thread.spawn 创建的“轻量级线程”,都是和创建它们的请求绑定的。如果你要创建和当前请求分离开的后台逻辑,应当使用 ngx.timer.at()

“轻线程”是自动往前不断(异步地)执行的,由 ngx_lua 的轻线程调度器自动调度,而不用你自己一次一次地 resume. 而 coroutine.create() 创建的常规协程并不会自动往前执行,而需要你自己通过 coroutine.resume() 同步地调用。 尽量不要让单个处理程序(包括 timer 回调)本身运行太久。

openresty源码剖析——lua代码的加载

http://www.cnblogs.com/magicsoar/p/6774872.html

玩转 OpenResty 协程 API

https://segmentfault.com/a/1190000009975651

Consul 简介、安装、常用命令的使用

http://blog.csdn.net/u010046908/article/details/61916389

使用consul实现分布式服务注册和发现

http://tonybai.com/2015/07/06/implement-distributed-services-registery-and-discovery-by-consul/

Lua按指定字符分隔字符串的3种方法

http://blog.csdn.net/forestsenlin/article/details/50590577

comments powered by Disqus