コルーチンの作成
coroutine.createとcoroutine.wrapでコルーチンを作成します。
「コルーチンの作成」はCoddyKit上の無料Lua Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLua Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Lua Academyコースには全4レッスンが含まれています。
コルーチンとは
コルーチンとは、実行を一時停止(yield)し、後から中断した場所から再開できる関数です。スレッドとは異なり、コルーチンは協調的に動作します。つまり、一度に実行されるのは 1 つだけで、明示的に制御を譲ります。Lua のコルーチンは独自のスタックとローカル変数を持ちます。
local co = coroutine.create(function()
print("start")
coroutine.yield()
print("resumed")
coroutine.yield()
print("done")
end)
print(coroutine.status(co)) -- suspended
coroutine.resume(co) -- start
print(coroutine.status(co)) -- suspended
coroutine.resume(co) -- resumedcoroutine.create と coroutine.wrap
coroutine.create(fn) はコルーチンを作成し、コルーチンオブジェクト(型は thread)を返します。coroutine.wrap(fn) はコルーチンを作成し、呼び出すとコルーチンを再開する関数を返します。wrap は簡単ですが、コルーチンオブジェクトは隠されます。
-- create: returns coroutine object
local co = coroutine.create(function(x)
return x * 2
end)
local ok, val = coroutine.resume(co, 5)
print(ok, val) -- true 10
-- wrap: returns a resumable function
local gen = coroutine.wrap(function(x)
return x * 3
end)
print(gen(5)) -- 15コルーチンのライフサイクル
コルーチンには 4 つの状態があります。suspended(実行されていない)、running(現在実行中)、dead(return またはエラーで終了)、normal(別のコルーチンを再開したため一時停止中)です。coroutine.status(co) で状態を確認できます。
local co = coroutine.create(function()
coroutine.yield()
end)
print(coroutine.status(co)) -- suspended
coroutine.resume(co) -- runs until yield
print(coroutine.status(co)) -- suspended again
coroutine.resume(co) -- runs until end
print(coroutine.status(co)) -- dead複数のコルーチンの実行
複数のコルーチンを作成し、それぞれを順番に再開して処理を交互に進めます。これにより、並行実行(協調的マルチタスク)をシミュレートできます。各コルーチンは yield の間も自身の状態を保持します。
local function worker(name, steps)
for i = 1, steps do
print(name .. ": step " .. i)
coroutine.yield()
end
end
local co1 = coroutine.create(function() worker("A", 3) end)
local co2 = coroutine.create(function() worker("B", 3) end)
for _ = 1, 3 do
coroutine.resume(co1)
coroutine.resume(co2)
end
-- A:1, B:1, A:2, B:2, A:3, B:3coroutine.wrap による反復
coroutine.wrap はイテレーターの作成によく使われます。返された関数を呼び出すたびに、イテレーターが次へ進みます。コルーチン本体が終了すると、この関数はエラーを発生させます。必要に応じて pcall を使うか、状態を確認してください。
local function range(n)
return coroutine.wrap(function()
for i = 1, n do
coroutine.yield(i)
end
end)
end
for v in range(5) do
io.write(v .. " ")
end
print() -- 1 2 3 4 5コルーチン内のエラー
コルーチンでエラーが発生すると、coroutine.resume は false に続けてエラーメッセージを返します。コルーチンは dead 状態に移行し、終了したコルーチンを再び再開することはできません。
local co = coroutine.create(function(x)
if x < 0 then error("negative input: " .. x) end
return math.sqrt(x)
end)
local ok, val = coroutine.resume(co, -1)
print(ok, val) -- false input:2: negative input: -1
print(coroutine.status(co)) -- dead
-- Can't resume a dead coroutine:
ok, val = coroutine.resume(co)
print(ok, val) -- false cannot resume dead coroutineコルーチンの識別
coroutine.running() は、現在実行中のコルーチンと、それがメインスレッドかどうかを示すブール値を返します。コルーチン内でこれを使うと、自身への参照を取得できます。
local co = coroutine.create(function()
local self, isMain = coroutine.running()
print("type:", type(self)) -- thread
print("isMain:", isMain) -- false
print("status:", coroutine.status(self)) -- running
end)
coroutine.resume(co)
-- In main thread:
local main, isMain = coroutine.running()
print("main isMain:", isMain) -- true無限ジェネレーター
コルーチン本体に yield を含む無限ループを記述できます。これにより、ジェネレーターは終了せず、要求に応じて値を生成します。これは、遅延評価される無限シーケンスという重要な用途です。
local function naturals(start)
return coroutine.wrap(function()
local n = start or 1
while true do
coroutine.yield(n)
n = n + 1
end
end)
end
local gen = naturals(1)
for i = 1, 8 do
io.write(gen() .. " ")
end
print() -- 1 2 3 4 5 6 7 8タスクとしてのコルーチン
基本的なタスクスケジューラーでは、コルーチンをキューに保存し、それぞれを順番に再開します。コルーチンが yield するとキューに戻し、終了すると削除します。これは最小限の協調型スケジューラーです。
local tasks = {}
local function spawn(fn)
tasks[#tasks+1] = coroutine.create(fn)
end
local function run()
while #tasks > 0 do
local alive = {}
for _, co in ipairs(tasks) do
coroutine.resume(co)
if coroutine.status(co) ~= "dead" then
alive[#alive+1] = co
end
end
tasks = alive
end
end
spawn(function() for i=1,3 do print("T1:"..i); coroutine.yield() end end)
spawn(function() for i=1,3 do print("T2:"..i); coroutine.yield() end end)
run()コルーチンのメモリ
各コルーチンには独自のスタックがあります。深い呼び出しチェーンでは、スタックが大きくなることがあります。高パフォーマンスが求められる場面では、同時に数千のコルーチンを作成して稼働させることは避けてください。可能な場合はコルーチンを再利用するか、プールを使用してください。
-- Coroutine pool concept
local pool = {}
local function getCoroutine(fn)
-- Reuse dead coroutine slots
for i, co in ipairs(pool) do
if coroutine.status(co) == "dead" then
pool[i] = coroutine.create(fn)
return pool[i]
end
end
local co = coroutine.create(fn)
pool[#pool+1] = co
return co
end
print("Pool pattern for coroutine reuse")クイックチェック
coroutine.create(fn)の直後、コルーチンはどの状態になりますか?
復習:コルーチンの作成
まとめ:
coroutine.create(fn)→ コルーチンオブジェクト、wrap(fn)→ 再開可能な関数- 状態:suspended → running → suspended/dead
coroutine.resume(co, ...)で開始または再開- resume中のエラー:false + エラーメッセージ、コルーチン → dead
while true do yield() endによる無限ジェネレーター- 協調的マルチタスクと遅延シーケンスに使用
よくある質問
「コルーチンの作成」レッスンは無料ですか?
はい。「コルーチンの作成」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Lua Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Lua Academyコースには全4レッスンが含まれています。
「コルーチンの作成」で何を学びますか?
coroutine.createとcoroutine.wrapでコルーチンを作成します。 ブラウザで直接実行するハンズオンコードでLua Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Lua Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのLua Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「コルーチンの作成」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このLua Academyレッスンでコードを書いて実行できますか?
はい。すべてのLua Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。