skynet指定的多个服务绑定同一个线程

为什么会需要多个服务绑定一个线程?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)
相关推荐
沐风ya2 小时前
skynet概述(service,lua虚拟机,架构设计,如何解决核心问题)
lua·skynet·actor
IMPYLH3 小时前
Lua 的 UTF-8 模块
开发语言·笔记·后端·游戏引擎·lua
钟智强16 天前
CVE-2025-49844高危预警:Redis Lua脚本引擎UAF漏洞深度剖析与POC实战
数据库·redis·web安全·junit·lua
闲人编程16 天前
聚合管道与复杂查询
开发语言·oracle·lua·match·查询·聚合·lookup
会周易的程序员17 天前
cNetgate物联网网关内存数据表和数据视图模块架构
c语言·c++·物联网·架构·lua·iot
会周易的程序员18 天前
cNetgate插件架构设计详解 动态库 脚本二开lua, python, javascript
javascript·c++·python·物联网·lua·iot
白太岁22 天前
Redis:(3) Lua 与 Redis、基于连接池的 Facade 模式封装
数据库·c++·redis·lua·外观模式
Maguyusi1 个月前
go 批量生成c++和lua proto文件
c++·golang·lua·protobuf
foxsen_xia1 个月前
Kamailio通过Lua写路由
开发语言·lua·信息与通信