完整课程入口:996 全套课程体系 | Lua 学习路径 | 幂尔框架 mirs.cn
Lua 的协程(coroutine)是协作式"用户态线程":同一时刻只有一个协程在跑,切换点完全由你自己用 coroutine.yield 声明。它没有锁、没有竞态,是游戏脚本里做"分帧执行、异步流程"最安全的工具——这也是它和真线程的本质区别。
四个核心 API 构成全部生命周期:create 创建后返回一个 thread 对象但不执行;resume 启动或恢复它,一路跑到 yield 或结束;yield 挂起并把值带回给 resume;status 查看当前是 suspended、running 还是 dead。
local co = coroutine.create(function(total)
for i = 1, total do
coroutine.yield(i)
end
return "done"
end)
release_print(coroutine.resume(co)) -- true 1
release_print(coroutine.resume(co)) -- true 2
release_print(coroutine.resume(co)) -- true done 字符串
批量刷 5000 个怪物的数据初始化如果一口气做完,主循环会卡死一帧。用协程把工作切片,每帧只处理一批:
local worker = coroutine.create(function(list)
for i, cfg in ipairs(list) do
initMonster(cfg)
if i % 200 == 0 then coroutine.yield() end -- 每 200 个让出一次
end
end)
-- 挂进引擎的循环触发器里,每帧 resume 一次
local ok = coroutine.resume(worker, monsterList)
if coroutine.status(worker) == "dead" then
release_print("初始化完成")
end
这就是最朴素的"分帧器"骨架:进度天然保存在协程内部,不需要额外的游标变量,中断与恢复都由调度器一句话完成。
协程的另一个高价值场景是把"回调地狱"拉直。把"等待玩家确认""等待服务器返回"封装成 yield 点,整段业务就能写成顺序代码,可读性远高于层层嵌套的回调。
错误处理要记住两条:协程内的 Lua 错误不会向外抛,而是通过 resume 的第一个返回值(false)和错误消息带回,所以每次 resume 都要检查 ok;需要完整栈信息时,在协程体内用 xpcall(主逻辑, debug.traceback) 包一层,resume 拿到的错误串就带着出错位置,排查联动功能时能省一半时间。
最后一个实用细节:协程对象本身有开销,但很小,按任务粒度创建即可;真正要避免的是在 yield 之后把宿主数据悄悄改掉——恢复点之间数据结构发生了变化,是协程逻辑出 bug 的最大来源,写代码时保持"yield 前后假设世界会变"的警惕即可。