Lua中是否存在类似JS、Python的多协程等待完成等效实现?
Lua中实现类似Promise.all/asyncio.gather的多协程等待功能
在JavaScript中,我们可以通过Promise.all等待多个异步任务完成并获取结果:
const [a, b] = await Promise.all([task1(), task2()])
在Python中,对应的实现是asyncio.gather:
a, b = await asyncio.gather(task1(), task2())
Lua中的实现方案
Lua标准库并没有内置类似coroutine.resume_all的方法,需要我们手动实现多协程等待的逻辑。以下是两种常见的实现方式:
1. 等待所有协程完成(收集所有结果/错误)
这个实现会等待所有协程执行完毕,无论是否出现错误,最后统一返回结果或错误信息:
function gather(...) local coros = {...} local results = {} local errors = {} local alive_count = #coros -- 初始化启动所有协程 for idx, co in ipairs(coros) do local ok, val = coroutine.resume(co) if not ok then errors[idx] = val alive_count = alive_count - 1 else if coroutine.status(co) == 'dead' then results[idx] = val alive_count = alive_count - 1 else results[idx] = {co = co, last_val = val} end end end -- 轮询直到所有协程结束 while alive_count > 0 do for idx, data in ipairs(results) do if type(data) == 'table' then local ok, val = coroutine.resume(data.co, data.last_val) if not ok then errors[idx] = val results[idx] = nil alive_count = alive_count - 1 else if coroutine.status(data.co) == 'dead' then results[idx] = val alive_count = alive_count - 1 else data.last_val = val end end end end end -- 返回结果或错误 if next(errors) then return false, errors else return true, table.unpack(results) end end
使用示例:
-- 模拟任务1:分步执行后返回结果 local function task1() for i = 1, 3 do coroutine.yield("task1 step " .. i) end return "task1 completed" end -- 模拟任务2:执行中抛出错误 local function task2() coroutine.yield("task2 step 1") error("task2 encountered an error") end local co1 = coroutine.create(task1) local co2 = coroutine.create(task2) local ok, res_or_err = gather(co1, co2) if not ok then print("执行错误:") for idx, err in pairs(res_or_err) do print(string.format("任务%d:%s", idx, err)) end else print("执行结果:", res_or_err) end
2. 快速失败模式(任一协程报错立即终止)
这个实现类似Promise.all的行为:只要有一个协程执行报错,就立即停止所有等待并返回错误:
function gather_fast_fail(...) local coros = {...} local results = {} local alive_count = #coros while alive_count > 0 do local err_info = nil for idx, co in ipairs(coros) do if coroutine.status(co) ~= 'dead' then local ok, val = coroutine.resume(co) if not ok then err_info = {task_idx = idx, msg = val} break end if coroutine.status(co) == 'dead' then results[idx] = val alive_count = alive_count - 1 end end end if err_info then return false, string.format("任务%d报错:%s", err_info.task_idx, err_info.msg) end end return true, table.unpack(results) end
使用这个函数时,只要任一任务报错,就会直接返回错误信息,不会等待其他任务完成。
内容的提问来源于stack exchange,提问作者Nil Admirari
相关产品推荐
相关产品推荐

