サーチ…


構文

  • coroutine.create(function)は、関数を含むコルーチン(型(coroutine)== 'スレッド')を返します。

  • coroutine.resume(co、...)は、コルーチンを再開したり、開始したりします。レジュームに与えられた追加の引数は、以前にコルーチンを一時停止していたcoroutine.yield()から返されます。コルーチンが起動していない場合、追加の引数が関数の引数になります。

  • coroutine.yield(...)は、現在実行中のコルーチンを生成します。コルーチンを開始したcoroutine.resume()の呼び出しの後に実行が選択されます。 yieldに与えられた引数は、コルーチンを開始した対応するcoroutine.resume()から返されます。

  • coroutine.status(co)はコルーチンの状態を返します。次のようになります。

    • 「死んでいる」:コルーチンの機能が終了し、コルーチンをもう再開できない
    • 「実行中」:コルーチンが再開され、実行中です。
    • "正常":コルーチンが別のコルーチンを再開しました
    • "中断":コルーチンが降伏し、再開を待っている
  • coroutine.wrap(関数)は、呼び出されたときにcoroutine.create(関数)によって作成されたであろうコルーチンを再開する関数を返します。

備考

コルーチンシステムは、他の言語で存在するマルチスレッドをエミュレートするためにluaで実装されています。それは人間のユーザが彼らが同時に実行されると思うように、異なる機能間で非常に高速で切り替えることによって動作します。

コルーチンを作成して使用する

コルーチンと対話するすべての機能は、 コルーチンテーブルで使用できます。新しいコルーチンは、1つの引数を指定してcoroutine.create関数を使用して作成されます。実行するコードを持つ関数:

thread1 = coroutine.create(function()
            print("honk")
        end)

print(thread1)
-->> thread: 6b028b8c

coroutineオブジェクトは、新しいコルーチンを表すthread型の値を返します。新しいコルーチンが作成されると、その初期状態は中断されます。

print(coroutine.status(thread1))
-->> suspended

コルーチンを再開または開始するには、関数coroutine.resumeが使用されます。最初の引数はスレッドオブジェクトです。

coroutine.resume(thread1)
-->> honk

これで、コルーチンはコードを実行して終了し、状態を死んだ状態に変え、再開できなくなります。

print(coroutine.status(thread1))
-->> dead

coroutineは実行を中断し、 coroutine.yield関数のおかげで後で再開できます:

thread2 = coroutine.create(function()
        for n = 1, 5 do
            print("honk "..n)
            coroutine.yield()
        end
    end)

ご覧のように、 coroutine.yield()はforループの内部にあり、コルーチンを再開すると、coroutine.yieldに達するまでコードを実行します:

coroutine.resume(thread2)
-->> honk 1
coroutine.resume(thread2)
-->> honk 2

ループが終了すると、スレッドのステータスは停止し 、再開できなくなります。 Coroutinesではデータ間の交換も可能です:

thread3 = coroutine.create(function(complement)
    print("honk "..complement)
    coroutine.yield()
    print("honk again "..complement)
end)
coroutine.resume(thread3, "stackoverflow")
-->> honk stackoverflow

コルーチンが余分な引数なしで再度実行される場合、 補数は最初のレジューム(この場合は "stackoverflow")の引き数になります。

coroutine.resume(thread3)
-->> honk again stackoverflow

最後に、コルーチンが終了すると、関数によって返された値はすべて対応するレジュームに移動します。

thread4 = coroutine.create(function(a, b)
    local c = a+b
    coroutine.yield()
    return c
end)
coroutine.resume(thread4, 1, 2)
print(coroutine.resume(thread4))
-->> true, 3

コルーチンは、再帰呼び出し内の深さから呼び出しスレッドに値を戻すために、この関数で使用されます。

local function Combinations(l, r)
    local ll = #l
    r = r or ll
    local sel = {}
    local function rhelper(depth, last)
        depth = depth or 1
        last = last or 1
        if depth > r then
            coroutine.yield(sel)
        else
            for i = last, ll - (r - depth) do
                sel[depth] = l[i]
                rhelper(depth+1, i+1)
            end
        end
    end
    return coroutine.wrap(rhelper)
end

for v in Combinations({1, 2, 3}, 2) do
    print("{"..table.concat(v, ", ").."}")
end
--> {1, 2}
--> {1, 3}
--> {2, 3}

コルーチンは、遅延評価にも使用できます。

-- slices a generator 'c' taking every 'step'th output from the generator
-- starting at the 'start'th output to the 'stop'th output
function slice(c, start, step, stop)
    local _
    return coroutine.wrap(function()
        for i = 1, start-1 do
            _ = c()
        end
        for i = start, stop do
            if (i - start) % step == 0 then
                coroutine.yield(c())
            else
                _ = c()
            end
        end
    end)
end


local alphabet = {}
for c = string.byte('a'), string.byte('z') do
    alphabet[#alphabet+1] = string.char(c)
end
-- only yields combinations 100 through 102
-- requires evaluating the first 100 combinations, but not the next 5311633
local s = slice(Combinations(alphabet, 10), 100, 1, 102)
for i in s do
    print(table.concat(i))
end
--> abcdefghpr
--> abcdefghps
--> abcdefghpt

コルーチンは、「 プログラミングでのプログラミング」で説明しているように、パイプ構造に使用できます。 PiLの著者、Roberto Ierusalimschyは、コルーチンを使用して継続性のようなより高度で一般的なフロー制御機構を実装するための論文を発表しました。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow