协程池
在 使用 Lua 协程模拟 Golang 的 go defer 编程模式 中介绍了 Lua 协程的使用,模仿 golang 封装了下
还可以做进一步的优化
原来的 go 函数是这样实现的:
function go(_co_task)
local co = coroutine.create(function(_co_wrap)
_co_task(_co_wrap)
invoke_defer_handlers(_co_wrap, {ok=true}) -- 正常退出
end)
local cowrap = { co = co, defer_handlers = {} } ---@type co_wrap
coroutine_resume(cowrap)
end
每go
一次,均coroutine.create
创建一根协程
阅读了 skynet 相关使用协程的代码,发现 skynet 使用了协程池
因此可以借鉴过来
具体实现
引入协程池的类似代码如下:
---@type co_wrap[]
local coroutine_pool = setmetatable({}, { __mode = "kv" })
local coroutine_max_idle_num = 10 -- 协程池,最大空闲个数
function go(_co_task)
local co_wrap_0 = table.remove(coroutine_pool) ---@type co_wrap
if not co_wrap_0 then
local co = coroutine.create(function()
while true do
local co_wrap_2, co_tesk_2 = coroutine.yield()
co_tesk_2(co_wrap_2)
invoke_defer_handlers(_co_wrap, {ok=true}) -- 正常退出
co_tesk_2 = nil
if #coroutine_pool < coroutine_max_idle_num then
coroutine_pool[#coroutine_pool + 1] = { co = co_wrap_2.co, defer_handlers = {} }
co_wrap_2 = nil
else
co_wrap_2 = nil
return
end
end
end)
continue.resume(co)
local co_wrap_1 = { co = co, defer_handlers = {} } ---@type co_wrap
coroutine_resume(co_wrap_1, co_wrap_1, _co_task)
else
-- 复用协程
coroutine_resume(co_wrap_0, co_wrap_0, _co_task)
end
end
- go 函数,pop coroutine_pool 队尾,如果不为空,则有协程可以复用;否则新建协程处理
- 因为协程需要复用,因此需要解耦 _co_task ,可以通过 resume 传递过去
- 还可以设置协程池大小。进而判断,压入 coroutine_pool 继续 yield 等待下个任务;还是直接结束本协程