On this page

Lua 协同程序(coroutine)

Lua 协同程序(Coroutine)全面解析

协同程序是 Lua 实现协作式多任务的强大特性,它比线程更轻量级,允许在单个线程中实现多任务调度。

1. 协同程序基础

创建协同程序

-- 创建协同程序
local co = coroutine.create(function(a, b)
    print("参数:", a, b)
    local sum = a + b
    coroutine.yield(sum)  -- 挂起并返回值
    return "完成"
end)

执行协同程序

-- 首次恢复执行
local ok, result = coroutine.resume(co, 10, 20)
print(ok, result)  -- 输出: true    30

-- 继续执行
ok, result = coroutine.resume(co)
print(ok, result)  -- 输出: true    完成

2. 协同程序状态

协同程序有以下几种状态:

  • suspended (挂起):刚创建或调用 yield 后
  • running (运行):正在执行
  • dead (结束):函数执行完毕
  • normal (正常):唤醒另一个协程时
print(coroutine.status(co))  -- 查看状态

3. 生产者-消费者模式

经典示例

-- 生产者
function producer()
    local i = 0
    return function()
        i = i + 1
        return i
    end
end

-- 消费者
function consumer(prod)
    while true do
        local value = prod()
        print("消费:", value)
        coroutine.yield()
    end
end

-- 创建生产者和消费者协同程序
local p = producer()
local co = coroutine.create(function() consumer(p) end)

-- 驱动消费
for i = 1, 5 do
    coroutine.resume(co)
end

4. 协同程序高级用法

双向通信

local co = coroutine.create(function()
    while true do
        local x = coroutine.yield()
        print("接收:", x)
    end
end)

coroutine.resume(co)  -- 启动协程
coroutine.resume(co, 10)  -- 发送10
coroutine.resume(co, 20)  -- 发送20

协程包装器

function coroWrapper(f)
    return function(...)
        local co = coroutine.create(f)
        return function(...)
            return coroutine.resume(co, ...)
        end
    end
end

-- 使用
local myCoro = coroWrapper(function(a, b)
    coroutine.yield(a + b)
    return a * b
end)

local resume = myCoro(3, 4)
print(resume())  -- 输出: true    7
print(resume())  -- 输出: true    12

5. 协同程序与迭代器

协程迭代器

function walk(dir)
    return coroutine.wrap(function()
        for name in io.popen("ls "..dir):lines() do
            coroutine.yield(name)
        end
    end)
end

-- 使用
for filename in walk("/path") do
    print(filename)
end

复杂数据生成

function permutations(arr)
    return coroutine.wrap(function()
        permgen(arr, #arr)
    end)
end

function permgen(a, n)
    if n <= 1 then
        coroutine.yield(a)
    else
        for i = 1, n do
            a[n], a[i] = a[i], a[n]
            permgen(a, n - 1)
            a[n], a[i] = a[i], a[n]
        end
    end
end

-- 使用
for p in permutations({"a", "b", "c"}) do
    print(table.concat(p, ", "))
end

6. 协同程序应用场景

  1. 状态机实现:每个状态对应一个 yield 点
  2. 游戏AI:为每个NPC分配一个协程
  3. 异步I/O模拟:配合事件循环
  4. 管道过滤:连接多个处理阶段
  5. 惰性求值:按需生成数据

7. 注意事项

  1. 不是真正的多线程:同一时间只有一个协程运行
  2. 避免阻塞操作:会阻塞整个程序
  3. 错误处理
    local ok, err = coroutine.resume(co)
    if not ok then
        print("协程错误:", err)
    end
    
  4. 资源清理:确保协程能正常结束

协同程序为 Lua 提供了强大的控制流抽象能力,合理使用可以写出既高效又易于理解的异步代码结构。