zoukankan      html  css  js  c++  java
  • 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("
    ")
    end
    print("----")
    for p in permutations_wrap({1, 2, 3}) do
        for i = 1, #p do io.write(p[i], " ") end
        io.write("
    ")
    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的协程,然后返回一个调用该协程的函数。

  • 相关阅读:
    log4j日志配置
    map和java对象的转换方法
    阿里巴巴的json使用时的一些转换方法
    HttpClient发送Post和Get请求
    IT网站导航
    python学习
    git解决冲突
    协程
    Python实现协程
    异步任务神器 和定时任务Celery
  • 原文地址:https://www.cnblogs.com/tangxin-blog/p/10310317.html
Copyright © 2011-2022 走看看