为什么会需要多个服务绑定一个线程?skynet节点的线程数量是可以配置的,但是你不可能配置非常多吧?如果我们一个节点有非常多的服务,我们想其中某些服务不能卡,那么就需要把服务绑定线程不和其他服务共享线程。
我们有一些服务,业务很简单,虽然不怎么吃资源,但是要求不能卡,都需要绑定线程,如果给每一个服务都绑定线程,剩下的留给其他服务共享,可能会资源浪费。绑定的服务消耗了太多的线程,饱的饱死,饿得饿死。
所以我们需要把那些需要独立线程,本身其实不怎么吃资源的,给他们绑定同一个线程。
-- thread_proxy.lua(线程代理服务)
Lua
-- thread_proxy.lua(线程代理服务)
local skynet = require "skynet"
local logger = require "base.logger"
local thread_id = nil -- 要绑定的线程ID(比如 3)
local target_services = {} -- 要共享该线程的3个服务
-- 注册需要共享线程的服务
function CMD.register_service(svc_name, svc_handle)
target_services[svc_name] = svc_handle
logger.info(string.format("服务%s注册到线程%d的代理", svc_name, thread_id))
end
-- 转发消息到目标服务
function CMD.forward_msg(svc_name, cmd, ...)
local svc = target_services[svc_name]
if not svc then
logger.error("服务未注册:", svc_name)
return
end
-- 在当前线程内调用目标服务的逻辑(核心:保证在同一个线程执行)
skynet.call(svc, "lua", cmd, ...)
end
skynet.start(function()
-- 1. 绑定到指定线程(thread_id需和配置的thread数匹配,比如3)
thread_id = tonumber(skynet.getenv("bind_thread_id")) or 3
skynet.set_thread(thread_id) -- 关键:绑定到指定ID的线程
logger.info("线程代理服务绑定到线程:", thread_id)
-- 2. 注册消息处理函数
skynet.dispatch("lua", function(session, source, cmd, ...)
local f = CMD[cmd]
if f then
skynet.ret(skynet.pack(f(...)))
else
skynet.ret(skynet.pack(nil, "未知命令:"..cmd))
end
end)
end)
-- target_service1.lua
Lua
-- target_service1.lua(目标服务1,2/3同理)
local skynet = require "skynet"
local logger = require "base.logger"
local proxy_svc = nil -- 线程代理服务的句柄
-- 实际业务逻辑(会在代理线程中执行)
function CMD.do_business(...)
logger.info("服务1在线程中处理业务:", ...)
-- 你的业务逻辑(比如场景管理、玩家数据处理)
return "success"
end
skynet.start(function()
-- 1. 获取线程代理服务句柄
proxy_svc = skynet.uniqueservice("thread_proxy")
-- 2. 注册到代理服务
skynet.call(proxy_svc, "lua", "register_service", "service1", skynet.self())
-- 3. 所有消息转发给代理
skynet.dispatch("lua", function(session, source, cmd, ...)
-- 转发到代理服务,由代理在指定线程中执行
local ret = skynet.call(proxy_svc, "lua", "forward_msg", "service1", cmd, ...)
skynet.ret(skynet.pack(ret))
end)
end)
-- 节点入口
Lua
-- 节点入口
local skynet = require "skynet"
skynet.start(function()
-- 1. 先启动线程代理服务(必须最先启动)
local proxy = skynet.uniqueservice("thread_proxy")
-- 2. 启动3个目标服务
local s1 = skynet.newservice("target_service1")
local s2 = skynet.newservice("target_service2")
local s3 = skynet.newservice("target_service3")
-- 3. 测试:调用3个服务的业务逻辑,验证都在线程3执行
skynet.call(s1, "lua", "do_business", "服务1测试")
skynet.call(s2, "lua", "do_business", "服务2测试")
skynet.call(s3, "lua", "do_business", "服务3测试")
end)