Lua-コルーチン

前書き

コルーチンは本質的に協調的であるため、2つ以上のメソッドを制御された方法で実行できます。コルーチンを使用すると、常に1つのコルーチンのみが実行され、この実行中のコルーチンは、明示的に一時停止を要求した場合にのみ実行を一時停止します。

上記の定義はあいまいに見えるかもしれません。メインプログラムメソッドとコルーチンの2つのメソッドがあると仮定します。resume関数を使用してコルーチンを呼び出すと、実行が開始され、yield関数を呼び出すと、実行が一時停止されます。この場合も、同じコルーチンは、中断された場所から別の再開関数呼び出しで実行を継続できます。このプロセスは、コルーチンの実行が終了するまで続行できます。

コルーチンで利用可能な機能

次の表に、Luaのコルーチンで使用可能なすべての関数とそれに対応する使用法を示します。

シニア番号 方法と目的
1

coroutine.create (f)

関数fを使用して新しいコルーチンを作成し、「thread」タイプのオブジェクトを返します。

2

coroutine.resume (co [, val1, ...])

コルーチンcoを再開し、パラメーターがある場合はそれを渡します。操作のステータスとオプションのその他の戻り値を返します。

3

coroutine.running ()

メインスレッドで呼び出された場合は、実行中のコルーチンまたはnilを返します。

4

coroutine.status (co)

コルーチンの状態に基づいて、実行中、正常、一時停止、または停止のいずれかの値を返します。

5

coroutine.wrap (f)

coroutine.createと同様に、coroutine.wrap関数もコルーチンを作成しますが、コルーチン自体を返す代わりに、呼び出されたときにコルーチンを再開する関数を返します。

6

coroutine.yield (...)

実行中のコルーチンを一時停止します。このメソッドに渡されるパラメーターは、resume関数への追加の戻り値として機能します。

コルーチンの概念を理解するための例を見てみましょう。

co = coroutine.create(function (value1,value2)
   local tempvar3 = 10
   print("coroutine section 1", value1, value2, tempvar3)
	
   local tempvar1 = coroutine.yield(value1+1,value2+1)
   tempvar3 = tempvar3 + value1
   print("coroutine section 2",tempvar1 ,tempvar2, tempvar3)
	
   local tempvar1, tempvar2= coroutine.yield(value1+value2, value1-value2)
   tempvar3 = tempvar3 + value1
   print("coroutine section 3",tempvar1,tempvar2, tempvar3)
   return value2, "end"
	
end)

print("main", coroutine.resume(co, 3, 2))
print("main", coroutine.resume(co, 12,14))
print("main", coroutine.resume(co, 5, 6))
print("main", coroutine.resume(co, 10, 20))

上記のプログラムを実行すると、次の出力が得られます。

coroutine section 1	3	2	10
main	true	4	3
coroutine section 2	12	nil	13
main	true	5	1
coroutine section 3	5	6	16
main	true	2	end
main	false	cannot resume dead coroutine

上記の例は何をしますか?

前述のように、resume関数を使用して操作を開始し、yield関数を使用して操作を停止します。また、コルーチンの再開機能によって受信された複数の戻り値があることがわかります。

  • まず、コルーチンを作成して変数名coに割り当て、コルーチンは2つの変数をパラメーターとして受け取ります。

  • 最初の再開関数を呼び出すと、値3と2は、コルーチンが終了するまで一時変数value1とvalue2に保持されます。

  • これを理解するために、最初は10であったtempvar3を使用しましたが、コルーチンの実行中はvalue1が3として保持されるため、その後のコルーチンの呼び出しによって13と16に更新されます。

  • 最初のcoroutine.yieldは、2つの値4と3をresume関数に返します。これは、yieldステートメントの入力パラメーター3と2を更新することで取得します。また、コルーチン実行の真/偽のステータスを受け取ります。

  • コルーチンに関するもう1つの点は、上記の例では、再開呼び出しの次のパラメーターがどのように処理されるかです。変数coroutine.yieldが次の呼び出しparamsを受け取ることがわかります。これは、既存のparam値を保持して新しい操作を実行する強力な方法を提供します。

  • 最後に、コルーチン内のすべてのステートメントが実行されると、後続の呼び出しはfalseで返され、応答として「デッドコルーチンを再開できません」ステートメントが返されます。

別のコルーチンの例

イールド関数とレジューム関数を使用して1から5までの数値を返す単純なコルーチンを見てみましょう。利用できない場合はコルーチンを作成するか、既存のコルーチンを再開します。

function getNumber()
   local function getNumberHelper()
      co = coroutine.create(function ()
      coroutine.yield(1)
      coroutine.yield(2)
      coroutine.yield(3)
      coroutine.yield(4)
      coroutine.yield(5)
      end)
      return co
   end
	
   if(numberHelper) then
      status, number = coroutine.resume(numberHelper);
		
      if coroutine.status(numberHelper) == "dead" then
         numberHelper = getNumberHelper()
         status, number = coroutine.resume(numberHelper);
      end
		
      return number
   else
      numberHelper = getNumberHelper()
      status, number = coroutine.resume(numberHelper);
      return number
   end
	
end

for index = 1, 10 do
   print(index, getNumber())
end

上記のプログラムを実行すると、次の出力が得られます。

1	1
2	2
3	3
4	4
5	5
6	1
7	2
8	3
9	4
10	5

コルーチンとマルチプログラミング言語のスレッドとの比較がよくありますが、コルーチンにはスレッドの同様の機能がありますが、一度に1つしか実行されず、同時に実行されることはないことを理解する必要があります。

特定の情報を一時的に保持することで、ニーズに合わせてプログラムの実行順序を制御します。コルーチンでグローバル変数を使用すると、コルーチンにさらに柔軟性が加わります。