Lua 的协同程序(coroutine)是轻量级线程(并非操作系统线程),用于实现协作式多任务编程。协同程序允许在函数执行过程中暂停(yield)和恢复(resume),从而灵活地控制程序的执行流。
1. 协同程序的基本概念
- 协同程序是 Lua 中的一种线程。
- 它与传统的多线程不同,协同程序是协作式的,即由程序显式地交出(yield)和恢复(resume)控制权。
- 协同程序通过
coroutine
库提供的 API 来操作。
1.1 协同程序的生命周期
协同程序的状态可以是以下几种:
- suspended:初始状态,或在调用
coroutine.yield()
后暂停。 - running:正在运行中。
- normal:正在 resume 另一个协同程序。
- dead:协同程序执行完毕,或没有更多的操作。
状态查看 API
函数 | 描述 |
---|---|
coroutine.status(co) |
返回协同程序的状态 |
coroutine.running() |
返回当前正在运行的协同程序 |
1.2 使用协同程序的基本 API
函数 | 描述 |
---|---|
coroutine.create(func) |
创建新的协同程序,返回协同程序句柄 |
coroutine.resume(co, ...) |
恢复协同程序的运行,可以传递参数 |
coroutine.yield(...) |
暂停协同程序的运行,返回给调用者 |
coroutine.status(co) |
获取协同程序的状态 |
coroutine.running() |
返回当前正在运行的协同程序句柄和是否是主协同程序 |
coroutine.wrap(func) |
创建一个协同程序,并返回一个可以直接调用的函数 |
2. 协同程序的基本使用
2.1 创建和运行协同程序
协同程序通过 coroutine.create()
创建,然后使用 coroutine.resume()
启动或恢复运行。
示例:基本协同程序
local co = coroutine.create(function()
print("Inside coroutine")
end)
print(coroutine.status(co)) -- 输出:suspended
coroutine.resume(co) -- 输出:Inside coroutine
print(coroutine.status(co)) -- 输出:dead
2.2 暂停和恢复协同程序
协同程序可以在运行过程中调用 coroutine.yield()
暂停自身,并将控制权交回调用者。随后可以通过 coroutine.resume()
恢复运行。
示例:暂停与恢复
local co = coroutine.create(function()
for i = 1, 3 do
print("Step", i)
coroutine.yield() -- 暂停协同程序
end
end)
coroutine.resume(co) -- 输出:Step 1
coroutine.resume(co) -- 输出:Step 2
coroutine.resume(co) -- 输出:Step 3
print(coroutine.status(co)) -- 输出:dead
2.3 传递参数和返回值
通过 coroutine.resume()
可以向协同程序传递参数,协同程序也可以通过 coroutine.yield()
返回值。
示例:协同程序参数和返回值
local co = coroutine.create(function(a, b)
print("Start coroutine", a, b)
local sum = a + b
local result = coroutine.yield(sum) -- 暂停并返回 sum
print("Resumed with", result)
end)
-- 第一次恢复
local status, sum = coroutine.resume(co, 10, 20)
print("Sum:", sum) -- 输出:Sum: 30
-- 第二次恢复
coroutine.resume(co, "Hello") -- 输出:Resumed with Hello
3. 高级用法
3.1 使用 coroutine.wrap
coroutine.wrap
创建一个协同程序,并返回一个可以直接调用的函数,无需显式调用 resume
。
示例:coroutine.wrap
local co = coroutine.wrap(function()
for i = 1, 3 do
print("Step", i)
coroutine.yield()
end
end)
co() -- 输出:Step 1
co() -- 输出:Step 2
co() -- 输出:Step 3
3.2 嵌套协同程序
协同程序可以在运行时调用另一个协同程序,实现嵌套协作。
示例:嵌套调用
local co1 = coroutine.create(function()
print("In co1")
coroutine.yield()
print("Back to co1")
end)
local co2 = coroutine.create(function()
print("In co2")
coroutine.resume(co1) -- 恢复 co1
print("Back to co2")
end)
coroutine.resume(co2)
输出:
In co2
In co1
Back to co2
Back to co1
3.3 实现生产者-消费者模型
协同程序可以用于实现生产者-消费者模型,其中一个协同程序生成数据,另一个协同程序消费数据。
示例:生产者-消费者
local function producer()
return coroutine.create(function()
for i = 1, 5 do
print("Producing", i)
coroutine.yield(i) -- 暂停并返回生产的值
end
end)
end
local function consumer(prod)
while true do
local status, value = coroutine.resume(prod)
if not status then break end
print("Consuming", value)
end
end
local prod = producer()
consumer(prod)
输出:
Producing 1
Consuming 1
Producing 2
Consuming 2
Producing 3
Consuming 3
Producing 4
Consuming 4
Producing 5
Consuming 5
3.4 用协同程序实现迭代器
协同程序可以实现自定义的迭代器,用于生成序列。
示例:生成器
local function range(start, stop, step)
return coroutine.wrap(function()
for i = start, stop, step do
coroutine.yield(i)
end
end)
end
for i in range(1, 10, 2) do
print(i)
end
输出:
1
3
5
7
9
4. 协同程序的应用场景
4.1 异步任务协调
协同程序可以用来模拟异步任务的行为,比如网络请求、文件操作等。
示例:任务调度器
local tasks = {}
local function create_task(func)
local co = coroutine.create(func)
table.insert(tasks, co)
end
local function run_tasks()
while #tasks > 0 do
local co = table.remove(tasks, 1)
local status = coroutine.resume(co)
if coroutine.status(co) ~= "dead" then
table.insert(tasks, co)
end
end
end
-- 定义任务
create_task(function()
for i = 1, 3 do
print("Task 1 - Step", i)
coroutine.yield()
end
end)
create_task(function()
for i = 1, 2 do
print("Task 2 - Step", i)
corout