Lua協同プログラム

4679 ワード

Lua協同プログラム
  • 作者:楊夢鳩
  • 校正:翟舒青
  • 協同(coroutine)とは?
    Lua協同プログラム(coroutine)はスレッドと比較して類似している:独立したスタック、独立した局所変数、独立した命令ポインタを持ち、同時に他の協同プログラムとグローバル変数と他の大部分のものを共有する.
    協同は非常に強力な機能ですが、使い勝手も複雑です.
    スレッドと協同プログラムの違い
    スレッドと協同プログラムの主な違いは、複数のスレッドを有するプログラムが複数のスレッドを同時に実行することができ、協同プログラムは互いに協力して実行する必要があることである.
    いずれかの指定された時点で1つの協同プログラムのみが実行され、この実行中の協同プログラムは、明確に要求された保留時にのみ保留されます.
    協同プログラムは同期したマルチスレッドに似ていて、同じスレッドロックを待っているいくつかのスレッドは少し協同しています.
    基本構文
    方法
    説明
    coroutine.create()
    coroutineを作成し、coroutineを返します.パラメータは関数で、resumeと組み合わせて使用すると関数呼び出しが呼び出されます.
    coroutine.resume()
    coroutineを再起動し、createと組み合わせて使用
    coroutine.yield()
    coroutineを掛け、coroutineを掛け状態に設定すると、resumeと組み合わせて多くの効果が得られます.
    coroutine.status()
    coroutineのステータスを表示注意:coroutineのステータスは3種類あります:dead、suspend、running、具体的にいつこのようなステータスがあるかは以下のプログラムを参照してください
    coroutine.wrap()
    coroutineを作成し、関数を返します.この関数を呼び出すとcoroutineに入り、create機能と重複します.
    coroutine.running()
    走っているcoroutineを返します.coroutineはスレッドで、runningを使用するとcoroutingのスレッド番号を返します.
    次の例では、上記の方法の使用方法を示します.
    -- coroutine_test.lua   
    co = coroutine.create(
        function(i)
            print(i);
        end
    )
     
    coroutine.resume(co, 1)   -- 1
    print(coroutine.status(co))  -- dead
     
    print("----------")
     
    co = coroutine.wrap(
        function(i)
            print(i);
        end
    )
     
    co(1)
     
    print("----------")
     
    co2 = coroutine.create(
        function()
            for i=1,10 do
                print(i)
                if i == 3 then
                    print(coroutine.status(co2))  --running
                    print(coroutine.running()) --thread:XXXXXX
                end
                coroutine.yield()
            end
        end
    )
     
    coroutine.resume(co2) --1
    coroutine.resume(co2) --2
    coroutine.resume(co2) --3
     
    print(coroutine.status(co2))   -- suspended
    print(coroutine.running())
     
    print("----------")
    

    上記の例の出力結果は、次のとおりです.
    1
    dead
    ----------
    1
    ----------
    1
    2
    3
    running
    thread: 0x7fb801c05868    false
    suspended
    thread: 0x7fb801c04c88    true
    ----------
    

    coroutine.runningではcoroutineが最下位で実装されていることがわかります.
    createがcoroutineを作成すると、新しいスレッドにイベントが登録されます.
    resumeを使用してイベントをトリガすると、createのcoroutine関数が実行され、yieldに遭遇すると現在のスレッドが保留され、resumeトリガイベントの再起動を待つことになります.
    次に、より詳細な例を分析します.
    function foo (a)
        print("foo     ", a)
        return coroutine.yield(2 * a) --     2*a   
    end
     
    co = coroutine.create(function (a , b)
        print("           ", a, b) -- co-body 1 10
        local r = foo(a + 1)
         
        print("           ", r)
        local r, s = coroutine.yield(a + b, a - b)  -- a,b               
         
        print("           ", r, s)
        return b, "      "                   -- b               
    end)
            
    print("main", coroutine.resume(co, 1, 10)) -- true, 4
    print("--   ----")
    print("main", coroutine.resume(co, "r")) -- true 11 -9
    print("---   ---")
    print("main", coroutine.resume(co, "x", "y")) -- true 10 end
    print("---   ---")
    print("main", coroutine.resume(co, "x", "y")) -- cannot resume dead coroutine
    print("---   ---")
    

    上記の例の出力結果は、次のとおりです.
                   1    10
    foo         2
    main    true    4
    --   ----
                   r
    main    true    11    -9
    ---   ---
                   x    y
    main    true    10          
    ---   ---
    main    false    cannot resume dead coroutine
    ---   ---
    

    次の例を示します.
  • はresumeを呼び出し、協同プログラムを起動し、resume操作はtrueに正常に戻り、そうでなければfalseに戻る.
  • 協同プログラム実行;
  • yield文に実行されます.
  • yieldは協同プログラムを掛け、初めてresumeが戻った.(注:ここでyieldはresumeのパラメータを返します)
  • 第2回resume、再び協同プログラムを起動する.(注:ここでresumeのパラメータでは、最初のパラメータを除いて、残りのパラメータはyieldのパラメータとして使用されます)
  • yieldが戻る.
  • 協同プログラムは引き続き実行する.
  • 使用する協同プログラムが実行を継続した後にresumeメソッドを呼び出し続ける場合、出力:cannot resume dead coroutine
  • resumeとyieldの協力の強さは、resumeがプライマリ・パスにあり、外部状態(データ)を協同プログラムの内部に伝達することである.一方yieldは内部の状態(データ)をメインパスに返す.
    生産者-消費者問題
    今、私はLuaの協同プログラムを使って生産者-消費者という古典的な問題を完成します.
    local newProductor
    
    function productor()
         local i = 0
         while true do
              i = i + 1
              send(i)     --             
         end
    end
    
    function consumer()
         while true do
              local i = receive()     --           
              print(i)
         end
    end
    
    function receive()
         local status, value = coroutine.resume(newProductor)
         return value
    end
    
    function send(x)
         coroutine.yield(x)     -- x        ,     ,        
    end
    
    --     
    newProductor = coroutine.create(productor)
    consumer()
    

    上記の例の出力結果は、次のとおりです.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    ……