skynet中使用skynet.call需要注意挂起的场景

在 skynet 框架中,skynet.call是一个同步调用函数,它会阻塞当前服务直到目标服务返回结果。这意味着如果目标服务执行时间很长或者没有返回结果,当前服务就会处于挂起状态,这可能会导致整个系统的性能下降或甚至崩溃,或因挂起导致逻辑重入,引发错误

1. 高延迟的外部调用

如果 skynet.call 用于调用外部服务(如数据库查询、HTTP 请求等),这些调用可能需要较长的时间。在这种情况下,使用 skynet.call 会导致当前服务长时间挂起

local httpc = require "skynet.http.client"
local result = skynet.call("HTTP_SERVICE", "lua", "get", "http://example.com/api/data")

解决方案:
使用 skynet.send 进行异步调用,并在回调中处理结果

local function on_response(result)
    -- 处理结果
end

skynet.send("HTTP_SERVICE", "lua", "get", "http://example.com/api/data", on_response)

2. 依赖多个服务的复杂逻辑

如果当前服务需要依赖多个其他服务的返回结果才能继续执行,使用 skynet.call 会导致多个服务同时挂起

local result1 = skynet.call("SERVICE1", "lua", "get_data")
local result2 = skynet.call("SERVICE2", "lua", "get_data")
local result3 = skynet.call("SERVICE3", "lua", "get_data")
-- 处理结果

解决方案:
使用异步方式并结合 skynet.wait 来处理多个异步调用

local results = {}
local count = 3

local function on_response(service, result)
    results[service] = result
    if #results == count then
        -- 处理结果
    end
end

skynet.send("SERVICE1", "lua", "get_data", on_response)
skynet.send("SERVICE2", "lua", "get_data", on_response)
skynet.send("SERVICE3", "lua", "get_data", on_response)

skynet.wait()

3. 循环调用

如果在循环中使用 skynet.call,每次调用都会导致当前服务挂起,可能导致被循环的table变化

local M = {}
M.services = {"SERVICE1", "SERVICE2", "SERVICE3"} -- 其他地方可能会insert或者remove这个table
for _, service in ipairs(M.services) do
    local result = skynet.call(service, "lua", "get_data")
    -- 处理结果
end

解决方案:
使用tmp缓存table进行循环调用

M.services = {"SERVICE1", "SERVICE2", "SERVICE3"} -- 其他地方可能会insert或者remove这个table
local tmp_services = {}
for _, service in ipairs(M.services) do
    table.insert(tmp_services, service)
end

for _, service in ipairs(tmp_services) do
    local result = skynet.call(service, "lua", "get_data")
    -- 处理结果
end

4. 无限循环或死锁

如果 skynet.call 调用的目标服务没有返回结果,或两个服务之间互相调用导致死锁,当前服务会永久挂起

-- Service A
local result = skynet.call("Service B", "lua", "get_data")

-- Service B
local result = skynet.call("Service A", "lua", "get_data")

解决方案:
避免服务之间的直接循环调用,使用中间服务或异步调用来打破死锁

-- Service A
skynet.send("Service B", "lua", "get_data")

-- Service B
local function on_request(source, ...)
    -- 处理请求并返回结果
end

skynet.dispatch("lua", on_request)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值