上文详细讲了沙盒服务 snlua 的启动过程。本文内容是snlua 服务收到消息后,如何进行调度。
协程调度
snlua 服务通过 skynet.start 进行启动。会触发绑定C消息回调函数
// 来自lua-skynet.c
static int
lcallback(lua_State *L) {
// 省略...
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD);
lua_State *gL = lua_tothread(L,-1);
skynet_callback(context, gL, _cb);
}
注意: callback 绑定的ud 是Lua VM的主协程。
因此,服务收到的消息,会驱动主协程执行 skynet.raw_dispatch_message.
那么,Lua VM 只用一个协程,来处理所有的消息吗?
不是的。实际上新的请求会对应一个协程。 协程创建的代码是
-- 来自 skynet.lua
local coroutine_pool = setmetatable({}, { __mode = "kv" })
local function co_create(f)
local co = table.remove(coroutine_pool)
if co == nil then
co = coroutine.create(function(...)
f(...)
while true do
f = nil
coroutine_pool[#coroutine_pool+1] = co
f = coroutine_yield "EXIT"
f(coroutine_yield())
end
end