协程状态
使用 coroutine.status 检查协程状态:running、suspended、dead。
协程状态 是 CoddyKit 上的免费 Lua Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Lua Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Lua Academy 课程共包含 4 节课。
协程的四种状态
协程有四种可能的状态:挂起(刚创建或执行了 yield,正在等待运行)、运行(当前正在执行)、正常(暂停运行,以便另一个协程运行)和已结束(执行完成或发生错误)。使用 coroutine.status(co) 查询状态。
local co = coroutine.create(function()
print(coroutine.status(coroutine.running())) -- running
coroutine.yield()
end)
print(coroutine.status(co)) -- suspended
coroutine.resume(co) -- prints: running
print(coroutine.status(co)) -- suspended
coroutine.resume(co)
print(coroutine.status(co)) -- dead“正常”状态
当一个协程恢复另一个协程时,它会进入“正常”状态。它并未运行(因为另一个协程正在运行),但也不是挂起状态——它正在等待被恢复的协程 yield。对于复杂的协程关系图,虽然这种状态并不常见,但理解它很重要。
local inner, outer
inner = coroutine.create(function()
print("outer status:", coroutine.status(outer)) -- normal
coroutine.yield()
end)
outer = coroutine.create(function()
coroutine.resume(inner)
end)
coroutine.resume(outer)
-- prints: outer status: normal恢复前进行检查
恢复协程前,请务必检查其状态,尤其是在循环中。恢复已结束的协程会产生错误。恢复正在运行的协程同样会产生错误(因为这会导致无限递归)。
local function safeResume(co, ...)
local status = coroutine.status(co)
if status == "dead" then
return false, "cannot resume dead coroutine"
end
if status == "running" then
return false, "cannot resume running coroutine"
end
return coroutine.resume(co, ...)
end发生错误后的状态
当协程主体函数引发未捕获的错误时,coroutine.resume 会返回 false 和错误消息。协程会转为“已结束”状态。它无法重新启动——如果要重试,必须创建一个新的协程。
local co = coroutine.create(function()
error("something went wrong")
end)
local ok, err = coroutine.resume(co)
print(ok, err) -- false ...: something went wrong
print(coroutine.status(co)) -- dead
-- Cannot resume dead coroutine:
local ok2, err2 = coroutine.resume(co)
print(ok2, err2) -- false cannot resume dead coroutinecoroutine.isyieldable
如果正在运行的协程可以执行 yield,coroutine.isyieldable() 就会返回 true。在主线程以及不支持 yield 的 C 函数中,它会返回 false。如果您不确定当前上下文,请在执行 yield 前进行检查。
local co = coroutine.create(function()
print("isyieldable:", coroutine.isyieldable()) -- true
coroutine.yield()
end)
coroutine.resume(co)
-- In main thread:
print("isyieldable:", coroutine.isyieldable()) -- false
-- coroutine.yield() -- ERROR in main thread监控一组协程
跟踪一个协程池,并在每轮恢复调用后移除已结束的协程。这是任务调度器的基础。
local function makeWorker(n, name)
return coroutine.create(function()
for i = 1, n do
print(name, "step", i)
coroutine.yield()
end
end)
end
local workers = {
makeWorker(2, "fast"),
makeWorker(4, "slow"),
}
while #workers > 0 do
local alive = {}
for _, co in ipairs(workers) do
coroutine.resume(co)
if coroutine.status(co) ~= "dead" then
alive[#alive+1] = co
end
end
workers = alive
end协程调试
使用状态检查来记录和调试基于协程的代码。打印状态转换,以便了解执行流程。在复杂系统中,可以通过包装器表为协程分配名称,从而获得更易读的调试输出。
local function namedCo(name, fn)
local co = coroutine.create(fn)
return {
co = co,
name = name,
resume = function(self, ...)
print("[" .. self.name .. "] resume")
local results = table.pack(coroutine.resume(self.co, ...))
print("[" .. self.name .. "] status: " .. coroutine.status(self.co))
return table.unpack(results, 1, results.n)
end
}
end
local worker = namedCo("worker1", function()
coroutine.yield()
end)
worker:resume()
worker:resume()重新启动已结束的协程
协程一旦结束,就无法再恢复。要“重新启动”它,必须使用同一个函数创建新的协程。常见的做法是使用工厂函数,按需创建全新的协程。
local function makeCounter(start, step)
return coroutine.wrap(function()
local n = start or 0
while true do
coroutine.yield(n)
n = n + (step or 1)
end
end)
end
local count = makeCounter(0, 2)
for i = 1, 5 do io.write(count() .. " ") end
print() -- 0 2 4 6 8
-- "Restart" by creating a new one
count = makeCounter(100)
print(count()) -- 100Coroutine.wrap 的错误行为
包装后的协程发生错误时,错误会从包装器函数调用中传播出来。与会返回 false+错误信息的 coroutine.resume 不同,由 wrap 返回的函数会直接引发错误。如果需要捕获错误,请在 wrap 调用外使用 pcall。
local gen = coroutine.wrap(function()
coroutine.yield(1)
error("oops")
coroutine.yield(2) -- never reached
end)
print(gen()) -- 1 (ok)
local ok, err = pcall(gen)
print(ok, err) -- false ...: oops
-- Subsequent call: dead coroutine
ok, err = pcall(gen)
print(ok, err) -- false cannot resume dead coroutineisyieldable 与 status 的区别
有两种方式可以查看协程上下文:coroutine.status(co) 提供特定协程的状态;coroutine.isyieldable() 用于判断当前执行上下文是否可以 yield。使用 status 检查其他协程;使用 isyieldable 检查当前环境是否可以安全地执行 yield。
local function maybeYield()
if coroutine.isyieldable() then
coroutine.yield()
else
-- in main thread or non-yieldable context
print("cannot yield here")
end
end
maybeYield() -- prints "cannot yield here" (main thread)
local co = coroutine.create(maybeYield)
coroutine.resume(co) -- yields successfully快速检查
协程执行完主体函数后会进入什么状态?
回顾:协程状态
总结:
- 状态:挂起 → 运行 ↔ 正常 → 已结束
coroutine.status(co)返回状态字符串- 已结束 = 执行完成或发生错误;无法再次恢复
coroutine.isyieldable()检查当前上下文是否可以 yield- 在循环中恢复协程前,请务必检查状态
- wrap 的错误会直接传播;resume 返回 false+错误
常见问题解答
「协程状态」课时是免费的吗?
是的 — 「协程状态」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Lua Academy 课程的其余内容,请升级到 CoddyKit PRO。 Lua Academy 课程共包含 4 节课。
「协程状态」这节课中我会学到什么?
使用 coroutine.status 检查协程状态:running、suspended、dead。 你通过在浏览器中直接运行的动手代码来练习 Lua Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Lua Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Lua Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「协程状态」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Lua Academy 课中编写并运行代码吗?
能。每节 Lua Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。