创建协程
使用 coroutine.create 和 coroutine.wrap 创建协程。
创建协程 是 CoddyKit 上的免费 Lua Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Lua Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Lua Academy 课程共包含 4 节课。
什么是协程?
协程是一种可以暂停执行(yield),并在之后从暂停位置继续执行的函数。与线程不同,协程是协作式的——同一时间只有一个协程运行,并且必须显式让出控制权。Lua 协程拥有自己的栈和局部变量。
local co = coroutine.create(function()
print("start")
coroutine.yield()
print("resumed")
coroutine.yield()
print("done")
end)
print(coroutine.status(co)) -- suspended
coroutine.resume(co) -- start
print(coroutine.status(co)) -- suspended
coroutine.resume(co) -- resumedcoroutine.create 与 coroutine.wrap
coroutine.create(fn) 会创建一个协程,并返回协程对象(类型为 thread)。coroutine.wrap(fn) 会创建一个协程,并返回一个函数;调用该函数时,协程会恢复执行。wrap 更简单,但会隐藏协程对象。
-- create: returns coroutine object
local co = coroutine.create(function(x)
return x * 2
end)
local ok, val = coroutine.resume(co, 5)
print(ok, val) -- true 10
-- wrap: returns a resumable function
local gen = coroutine.wrap(function(x)
return x * 3
end)
print(gen(5)) -- 15协程生命周期
协程有四种状态:挂起(未运行)、运行中(当前正在执行)、已结束(已返回或发生错误),以及普通(由于恢复了另一个协程而暂停)。使用 coroutine.status(co) 检查状态。
local co = coroutine.create(function()
coroutine.yield()
end)
print(coroutine.status(co)) -- suspended
coroutine.resume(co) -- runs until yield
print(coroutine.status(co)) -- suspended again
coroutine.resume(co) -- runs until end
print(coroutine.status(co)) -- dead运行多个协程
创建多个协程,依次恢复每个协程,以交错方式运行它们。这样可以模拟并发执行(协作式多任务处理)。每个协程都会在让出控制权期间保留自己的状态。
local function worker(name, steps)
for i = 1, steps do
print(name .. ": step " .. i)
coroutine.yield()
end
end
local co1 = coroutine.create(function() worker("A", 3) end)
local co2 = coroutine.create(function() worker("B", 3) end)
for _ = 1, 3 do
coroutine.resume(co1)
coroutine.resume(co2)
end
-- A:1, B:1, A:2, B:2, A:3, B:3coroutine.wrap 迭代
coroutine.wrap 常用于创建迭代器。迭代器每前进一次,就调用一次返回的函数。当协程主体结束时,该函数会引发错误——如有需要,请使用 pcall 或检查状态。
local function range(n)
return coroutine.wrap(function()
for i = 1, n do
coroutine.yield(i)
end
end)
end
for v in range(5) do
io.write(v .. " ")
end
print() -- 1 2 3 4 5协程中的错误
如果协程引发错误,coroutine.resume 会返回 false,后面跟着错误消息。该协程会转换为 dead 状态。已结束的协程无法再次恢复。
local co = coroutine.create(function(x)
if x < 0 then error("negative input: " .. x) end
return math.sqrt(x)
end)
local ok, val = coroutine.resume(co, -1)
print(ok, val) -- false input:2: negative input: -1
print(coroutine.status(co)) -- dead
-- Can't resume a dead coroutine:
ok, val = coroutine.resume(co)
print(ok, val) -- false cannot resume dead coroutine协程身份
coroutine.running() 会返回当前正在运行的协程,以及一个表示它是否为主线程的布尔值。在协程内部使用它可以获取对自身的引用。
local co = coroutine.create(function()
local self, isMain = coroutine.running()
print("type:", type(self)) -- thread
print("isMain:", isMain) -- false
print("status:", coroutine.status(self)) -- running
end)
coroutine.resume(co)
-- In main thread:
local main, isMain = coroutine.running()
print("main isMain:", isMain) -- true无限生成器
协程主体可以包含一个内部带有 yield 的无限循环——生成器按需生成值,而不会终止。这是协程的一个重要用途:生成延迟计算的无限序列。
local function naturals(start)
return coroutine.wrap(function()
local n = start or 1
while true do
coroutine.yield(n)
n = n + 1
end
end)
end
local gen = naturals(1)
for i = 1, 8 do
io.write(gen() .. " ")
end
print() -- 1 2 3 4 5 6 7 8将协程作为任务
一种基本的任务调度器是:将协程存储在队列中,然后依次恢复每个协程。当协程让出控制权时,将其放回队列;当协程结束时,将其移除。这是一个最小化的协作式调度器。
local tasks = {}
local function spawn(fn)
tasks[#tasks+1] = coroutine.create(fn)
end
local function run()
while #tasks > 0 do
local alive = {}
for _, co in ipairs(tasks) do
coroutine.resume(co)
if coroutine.status(co) ~= "dead" then
alive[#alive+1] = co
end
end
tasks = alive
end
end
spawn(function() for i=1,3 do print("T1:"..i); coroutine.yield() end end)
spawn(function() for i=1,3 do print("T2:"..i); coroutine.yield() end end)
run()协程内存
每个协程都有自己的栈。对于很深的调用链,栈可能会增长得很大。在高性能场景中,应避免创建成千上万个同时存活的协程。请尽可能重用协程,或使用协程池。
-- Coroutine pool concept
local pool = {}
local function getCoroutine(fn)
-- Reuse dead coroutine slots
for i, co in ipairs(pool) do
if coroutine.status(co) == "dead" then
pool[i] = coroutine.create(fn)
return pool[i]
end
end
local co = coroutine.create(fn)
pool[#pool+1] = co
return co
end
print("Pool pattern for coroutine reuse")快速检查
在执行 coroutine.create(fn) 后,协程立即处于什么状态?
回顾:创建协程
总结:
coroutine.create(fn)→ 协程对象;wrap(fn)→ 可恢复的函数- 状态:挂起 → 运行 → 挂起/已结束
coroutine.resume(co, ...)启动或恢复协程- 恢复期间发生错误:返回 false 和错误消息;协程变为已结束
- 通过
while true do yield() end创建无限生成器 - 用于协作式多任务处理和惰性序列
常见问题解答
「创建协程」课时是免费的吗?
是的 — 「创建协程」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Lua Academy 课程的其余内容,请升级到 CoddyKit PRO。 Lua Academy 课程共包含 4 节课。
「创建协程」这节课中我会学到什么?
使用 coroutine.create 和 coroutine.wrap 创建协程。 你通过在浏览器中直接运行的动手代码来练习 Lua Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Lua Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Lua Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「创建协程」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Lua Academy 课中编写并运行代码吗?
能。每节 Lua Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。