协程 #
一、协程概述 #
1.1 什么是协程 #
协程是一种轻量级的并发机制,也称为"协作式多任务"。与线程不同,协程由程序自己控制切换,而不是由操作系统调度。
1.2 协程的特点 #
- 轻量:创建成本低,内存占用小
- 协作式:由程序控制切换时机
- 非抢占:不会被强制中断
- 单线程:同一时刻只有一个协程执行
1.3 协程状态 #
lua
-- 协程有四种状态
-- suspended:挂起(初始状态)
-- running:运行中
-- normal:正常(唤醒其他协程时)
-- dead:结束
二、协程基础 #
2.1 创建协程 #
lua
-- 方式1:coroutine.create
local co = coroutine.create(function()
print("协程执行")
end)
print(coroutine.status(co)) -- suspended
-- 方式2:coroutine.wrap(返回函数)
local cofunc = coroutine.wrap(function()
print("协程执行")
end)
cofunc() -- 直接调用
2.2 启动和恢复协程 #
lua
local co = coroutine.create(function()
print("协程开始")
coroutine.yield()
print("协程继续")
end)
print(coroutine.status(co)) -- suspended
coroutine.resume(co) -- 协程开始
print(coroutine.status(co)) -- suspended
coroutine.resume(co) -- 协程继续
print(coroutine.status(co)) -- dead
2.3 yield 和 resume #
lua
local co = coroutine.create(function()
for i = 1, 5 do
print("协程:" .. i)
coroutine.yield(i)
end
return "完成"
end)
for i = 1, 6 do
local ok, value = coroutine.resume(co)
print("主线程收到:" .. tostring(value))
end
-- 协程:1
-- 主线程收到:1
-- 协程:2
-- 主线程收到:2
-- ...
2.4 传递参数 #
lua
-- resume 传递参数给协程
local co = coroutine.create(function(x, y)
print("收到:" .. x .. ", " .. y)
local a, b = coroutine.yield(x + y)
print("继续收到:" .. a .. ", " .. b)
return a * b
end)
local ok, result = coroutine.resume(co, 10, 20)
print("结果:" .. result) -- 30
ok, result = coroutine.resume(co, 3, 4)
print("结果:" .. result) -- 12
三、协程函数 #
3.1 coroutine.create #
lua
-- 创建协程,返回协程对象
local co = coroutine.create(function()
print("Hello")
end)
3.2 coroutine.resume #
lua
-- 恢复协程执行
local co = coroutine.create(function()
return "result"
end)
local ok, result = coroutine.resume(co)
print(ok, result) -- true result
3.3 coroutine.yield #
lua
-- 挂起协程
local co = coroutine.create(function()
local x = coroutine.yield("first")
print("收到:" .. x)
return "done"
end)
local ok, value = coroutine.resume(co)
print(value) -- first
ok, value = coroutine.resume(co, "hello")
-- 收到:hello
print(value) -- done
3.4 coroutine.status #
lua
-- 获取协程状态
local co = coroutine.create(function()
coroutine.yield()
end)
print(coroutine.status(co)) -- suspended
coroutine.resume(co)
print(coroutine.status(co)) -- suspended
coroutine.resume(co)
print(coroutine.status(co)) -- dead
3.5 coroutine.running #
lua
-- 获取当前运行的协程
local current_co
local co = coroutine.create(function()
current_co = coroutine.running()
print("当前协程:" .. tostring(current_co))
end)
coroutine.resume(co)
print("是否是主线程:" .. tostring(current_co == nil))
3.6 coroutine.wrap #
lua
-- 创建协程并返回函数
local func = coroutine.wrap(function()
for i = 1, 3 do
coroutine.yield(i)
end
end)
print(func()) -- 1
print(func()) -- 2
print(func()) -- 3
print(func()) -- nil(协程结束)
四、协程应用 #
4.1 迭代器 #
lua
-- 使用协程创建迭代器
local function range_iter(max)
return coroutine.wrap(function()
for i = 1, max do
coroutine.yield(i)
end
end)
end
for i in range_iter(5) do
print(i)
end
-- 1 2 3 4 5
-- 遍历二叉树
local function traverse(tree)
return coroutine.wrap(function()
if tree then
for v in traverse(tree.left) do
coroutine.yield(v)
end
coroutine.yield(tree.value)
for v in traverse(tree.right) do
coroutine.yield(v)
end
end
end)
end
4.2 生产者-消费者 #
lua
-- 生产者
local function producer()
return coroutine.create(function()
for i = 1, 10 do
print("生产:" .. i)
coroutine.yield(i)
end
end)
end
-- 消费者
local function consumer(prod)
while true do
local ok, value = coroutine.resume(prod)
if not ok or not value then
break
end
print("消费:" .. value)
end
end
local prod = producer()
consumer(prod)
4.3 任务调度器 #
lua
local Scheduler = {}
Scheduler.__index = Scheduler
function Scheduler:new()
return setmetatable({tasks = {}}, self)
end
function Scheduler:add(func)
local co = coroutine.create(func)
table.insert(self.tasks, co)
return co
end
function Scheduler:run()
while #self.tasks > 0 do
local co = table.remove(self.tasks, 1)
local ok, delay = coroutine.resume(co)
if ok and coroutine.status(co) ~= "dead" then
if delay then
-- 延迟任务
table.insert(self.tasks, co)
else
-- 立即重新调度
table.insert(self.tasks, 1, co)
end
end
end
end
-- 使用
local scheduler = Scheduler:new()
scheduler:add(function()
for i = 1, 3 do
print("任务A:" .. i)
coroutine.yield(true) -- 让出控制权
end
end)
scheduler:add(function()
for i = 1, 3 do
print("任务B:" .. i)
coroutine.yield(true)
end
end)
scheduler:run()
-- 任务A:1
-- 任务B:1
-- 任务A:2
-- 任务B:2
-- 任务A:3
-- 任务B:3
4.4 异步操作模拟 #
lua
local Async = {}
function Async.sleep(ms)
coroutine.yield({type = "sleep", duration = ms})
end
function Async.fetch(url)
coroutine.yield({type = "fetch", url = url})
end
local function run_async(func)
local co = coroutine.create(func)
local ok, op
local function resume(result)
ok, op = coroutine.resume(co, result)
if ok and coroutine.status(co) ~= "dead" then
if op.type == "sleep" then
-- 模拟异步等待
local timer = os.time() + op.duration / 1000
while os.time() < timer do end
resume()
elseif op.type == "fetch" then
-- 模拟网络请求
resume({data = "Response from " .. op.url})
end
end
end
resume()
end
-- 使用
run_async(function()
print("开始")
Async.sleep(1000)
print("等待后")
local response = Async.fetch("https://api.example.com")
print("响应:" .. response.data)
end)
4.5 状态机 #
lua
local function state_machine()
return coroutine.wrap(function()
while true do
-- 状态 A
print("状态 A")
local input = coroutine.yield("A")
if input == "next" then
-- 状态 B
print("状态 B")
input = coroutine.yield("B")
if input == "next" then
-- 状态 C
print("状态 C")
input = coroutine.yield("C")
end
end
end
end)
end
local sm = state_machine()
print("当前状态:" .. sm()) -- 状态 A
print("当前状态:" .. sm("next")) -- 状态 B
print("当前状态:" .. sm("next")) -- 状态 C
五、协程与错误处理 #
5.1 错误传播 #
lua
local co = coroutine.create(function()
error("协程错误")
end)
local ok, err = coroutine.resume(co)
if not ok then
print("协程错误:" .. err)
end
5.2 安全执行 #
lua
local function safe_resume(co, ...)
local ok, result = coroutine.resume(co, ...)
if not ok then
print("错误:" .. result)
return nil
end
return result
end
六、协程与管道 #
6.1 管道模式 #
lua
local function pipeline(...)
local stages = {...}
return function(input)
local current = input
for _, stage in ipairs(stages) do
current = stage(current)
end
return current
end
end
-- 使用协程实现流式处理
local function stream_processor(processor)
return coroutine.wrap(function()
while true do
local input = coroutine.yield()
if input == nil then break end
processor(input)
end
end)
end
local filter = stream_processor(function(x)
if x % 2 == 0 then
print("偶数:" .. x)
end
end)
for i = 1, 10 do
filter(i)
end
七、总结 #
本章介绍了 Lua 协程:
- 协程概念:轻量级并发机制
- 协程状态:suspended、running、normal、dead
- 基本操作:create、resume、yield、wrap
- 应用场景:迭代器、生产者消费者、任务调度
- 异步模拟:sleep、fetch 等异步操作
- 状态机:使用协程实现状态转换
下一章,我们将学习 Lua 框架与应用。
最后更新:2026-03-27