lua coroutine

Lua中协程都放在表coroutine中。

Lua协程的四个状态

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

Lua协程的操作函数:

创建协程:coroutine.create(func)

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

例如:

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

输出:

thread

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

参数:可以分为两种情况。

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

例如:

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

输出:

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")

输出:

co1	hello
co2	world

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

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

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

例如:

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))

输出:

true	hello	world
true	hello	lua
false	cannot resume dead coroutine

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

挂起协程: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的协程,然后返回一个调用该协程的函数。

posted @ 2019-01-23 17:28  你好阿汤哥  Views(603)  Comments(0Edit  收藏  举报