Lua学習の道(十五)----Lua協同プログラム(coroutine)

61612 ワード

協同(coroutine)とは?
Lua協同プログラム(coroutine)はスレッドと比較して類似している:独立したスタック、独立した局所変数、独立した命令ポインタを持ち、同時に他の協同プログラムとグローバル変数と他の大部分のものを共有する.
協同は非常に強力な機能ですが、使い勝手も複雑です.
スレッドと協同プログラムの違い
スレッドと協同プログラムの主な違いは、複数のスレッドを有するプログラムが複数のスレッドを同時に実行することができ、協同プログラムは互いに協力して実行する必要があることである.
いずれかの指定された時点で1つの協同プログラムのみが実行され、この実行中の協同プログラムは、明確に要求された保留時にのみ保留されます.
協同プログラムは同期したマルチスレッドに似ていて、同じスレッドロックを待っているいくつかのスレッドは少し協同しています.
基本構文
方法
説明
coroutine.create()
coroutineを作成し、coroutineを返します.パラメータは関数で、resumeと組み合わせて使用すると関数呼び出しが呼び出されます.
coroutine.resume()
coroutineを再起動し、createと組み合わせて使用
coroutine.yield()
coroutineをサスペンドし、coroutineをサスペンド状態に設定します.これはresumeと組み合わせて使用すると多くの効果があります.最初の戻りパラメータ:起動に成功するとtrueが返され、起動に失敗してfalseが返され、2番目のパラメータが関数の戻り値です.
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  --              coroutine
                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   ,        yield,    
end
 
co = coroutine.create(function (a , b)
    print("           ", a, b) -- co-body 1 10
    local r = foo(a + 1)  --  foo      ,r       yield    ,     resume      “r”
     
    print("           ", r)
    local r, s = coroutine.yield(a + b, a - b)  -- ab               ,coroutine.yield       ,       resume   

     
    print("           ", r, s)    
    return b, "      "                   -- b               
end)
        
print("main", coroutine.resume(co, 1, 10)) -- true, 4       ,          yield    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() --             (       coroutine)

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