lua coroutine

Lua中协程都放在表coroutine中。函数

Lua协程的四个状态

  1. 挂起(suspended):一个协程被建立的时候,处于挂起状态,不会自动运行。
  2. 运行(running):coroutine.resume()用于启动或者再次启动一个协程,使其变成运行状态。
  3. 正常(normal):协程A唤醒协程B的时候,协程B处于运行状态,协程A就处于正常状态。
  4. 死亡(dead):协程中包含的函数执行完毕,协程就变成了死亡状态。

Lua协程的操做函数:

建立协程:coroutine.create(func)

该函数接受一个函数做为参数,返回一个thread类型的值。

例如:lua

local co = coroutine.create(function() print("hello") end)
print(type(co))

输出:线程

thread

启动协程:coroutine.resume(co, arg1, arg2, ...)

参数:能够分为两种状况。

1.协程中不包含yield():第一个参数是被启动的协程,后面的参数传递给协程封装的函数做为参数。

例如:code

local co = coroutine.create(
    function(a, b) 
        print("a + b =", a + b) 
    end
)
coroutine.resume(co, 1, 2)

输出:orm

a + b = 3

2.协程中包含yield():第一个参数仍是被启动的线程,在首次调用resume时,后面的参数传递给协程封装的函数做为参数;而再次调用(非首次)resume()时,后面的参数将做为yield()的返回值。
例如:协程

local co = coroutine.create(
    function(x) 
        print("co1", x) 
        print("co2", coroutine.yield()) 
    end
)
coroutine.resume(co, "hello")
coroutine.resume(co, "world")

输出:it

co1 hello
co2 world

返回值:分为三种状况。
1.协程没有结束,resume()第一个返回值是true,后面的返回值是yield(...)中的参数。

2.协程结束时,resume()第一个返回值是true,后面的返回值是协程中函数的返回值。

3.协程结束后,此时不该该继续调用resume,若是调用了,resume()第一个返回值是false,表示调用失败,第二个返回值是报错信息。

例如:io

local co = coroutine.create(
    function()
        coroutine.yield("hello", "world")
        return "hello", "lua"
    end
)
print(coroutine.resume(co))
print(coroutine.resume(co))
print(coroutine.resume(co))

输出:function

true    hello   world
true    hello   lua
false   cannot resume dead coroutine

值得注意的是,resume运行在保护模式中,若是协程在执行过程当中遇到了错误,Lua不会打印错误信息,而是把错误信息做为resume()的返回值。class

挂起协程:coroutine.yield(arg1, arg2, ...)

参数:yield()将做为本次唤醒协程的resume()的返回值。

返回值:下次唤醒协程的resume()的参数,将做为yield()的返回值。
例如:

local co = coroutine.create(
    function()
        local ret = coroutine.yield("hello")
        print(ret)
    end
)
local state, ret = coroutine.resume(co)
print(state)
print(ret)
coroutine.resume(co, "world")

输出:

true
hello
world

Lua协程的特色

Lua协程是一种非对称协程(asymmetric coroutine),须要两个函数来控制协程的执行,一个用于挂起协程,一个用于恢复协程。
相对于其余语言提供的对称协程(symmetric coroutine),只提供一个函数用于切换不一样协程之间的控制权。

Lua协程的一些应用

1.生产者消费者问题:

1.消费者驱动型

-- 消费者驱动型 consumer-driven
producer_co = coroutine.create(
    function()
        for i = 1, 5 do
            print("produce:", i)
            coroutine.yield(i)
        end
    end
)

function consumer()
    while true do
        local status, value = coroutine.resume(producer_co)
        print("producer:", coroutine.status(producer_co))
        if not value then
            break
        end
        print("consume:", value)
    end
end

consumer()

输出:

produce:    1
producer:   suspended
consume:    1
produce:    2
producer:   suspended
consume:    2
produce:    3
producer:   suspended
consume:    3
produce:    4
producer:   suspended
consume:    4
produce:    5
producer:   suspended
consume:    5
producer:   dead

2.生产者驱动型

-- 生产者驱动型 producer-driven
function producer()
    for i = 1, 5 do
       print("produce:", i)
       coroutine.resume(consumer_co, i)
       print("consumer:", coroutine.status(consumer_co))
    end
    coroutine.resume(consumer_co)
end

consumer_co = coroutine.create(
    function(x)
       while true do
         print("consume:", x)
         x = coroutine.yield()
         if not x then
          break
         end
       end
    end
)

producer()
print("consumer:", coroutine.status(consumer_co))

输出:

produce:    1
consume:    1
consumer:   suspended
produce:    2
consume:    2
consumer:   suspended
produce:    3
consume:    3
consumer:   suspended
produce:    4
consume:    4
consumer:   suspended
produce:    5
consume:    5
consumer:   suspended
consumer:   dead

2.将协程用做迭代器:

-- 产生全排列的迭代器
function permutation_gen(a, n)
    n = n or #a
    if n < 1 then
        coroutine.yield(a)
    else
        for i = 1, n do
            a[n], a[i] = a[i], a[n]
            permutation_gen(a, n - 1)
            a[n], a[i] = a[i], a[n]
        end
    end
end

function permutations(a)
    local co = coroutine.create(function() permutation_gen(a) end)
    return function()
        local code, res = coroutine.resume(co)
        return res
    end
end

function permutations_wrap(a)
    return coroutine.wrap(function() permutation_gen(a) end)
end

for p in permutations({1, 2, 3}) do
    for i = 1, #p do io.write(p[i], " ") end
    io.write("\n")
end
print("----")
for p in permutations_wrap({1, 2, 3}) do
    for i = 1, #p do io.write(p[i], " ") end
    io.write("\n")
end

输出:

2 3 1 
3 2 1 
3 1 2 
1 3 2 
2 1 3 
1 2 3 
----
2 3 1 
3 2 1 
3 1 2 
1 3 2 
2 1 3 
1 2 3

其中coroutine.warp(func)方法就是建立一个封装func的协程,而后返回一个调用该协程的函数。