resume и yield
Обменивайтесь данными между вызывающим кодом и сопрограммой с помощью resume/yield.
«resume и yield» — бесплатный урок Lua Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Lua Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Lua Academy содержит 4 уроков всего.
Передача значений корутине
Аргументы, переданные в первый вызов coroutine.resume, становятся параметрами функции, лежащей в основе корутины. Аргументы, переданные в последующие вызовы возобновления, возвращаются вызовом coroutine.yield(), который приостановил корутину.
local co = coroutine.create(function(a, b)
print("received:", a, b) -- 10 20
local c = coroutine.yield() -- pauses
print("after yield:", c) -- 30
end)
coroutine.resume(co, 10, 20) -- first call: passes a,b
coroutine.resume(co, 30) -- subsequent: passed to yieldЗначения из yield
Значения, переданные в coroutine.yield(val1, val2), становятся возвращаемыми значениями вызова coroutine.resume(), приостановившегося на yield. Таким образом, yield «возвращает» значения вызывающему коду.
local co = coroutine.create(function()
coroutine.yield(1, "hello")
coroutine.yield(2, "world")
return 3, "done"
end)
local ok, a, b = coroutine.resume(co)
print(ok, a, b) -- true 1 hello
ok, a, b = coroutine.resume(co)
print(ok, a, b) -- true 2 world
ok, a, b = coroutine.resume(co)
print(ok, a, b) -- true 3 doneДвунаправленный обмен данными
Корутины обеспечивают настоящий двунаправленный обмен данными: вызывающий код передаёт данные через resume, корутина обрабатывает их и возвращает результаты через yield. Каждый вызов resume/yield представляет собой синхронный обмен.
local co = coroutine.create(function(x)
while true do
x = coroutine.yield(x * x) -- yield x^2, get next x
end
end)
coroutine.resume(co) -- start (x=nil initially)
local ok, sq
ok, sq = coroutine.resume(co, 3); print(sq) -- 9
ok, sq = coroutine.resume(co, 5); print(sq) -- 25
ok, sq = coroutine.resume(co, 7); print(sq) -- 49Производитель и потребитель
Классический шаблон использования корутин: производитель выдаёт элементы по одному, а потребитель возобновляет производителя, когда ему нужен следующий элемент. Ни один из них не опережает другой — идеальная синхронизация.
local function producer(items)
return coroutine.create(function()
for _, item in ipairs(items) do
coroutine.yield(item)
end
end)
end
local pro = producer({"apple","banana","cherry"})
-- Consumer drives the loop
while true do
local ok, item = coroutine.resume(pro)
if not ok or item == nil then break end
print("consumed:", item)
endКонвейер с корутинами
Объединяйте несколько корутин в конвейер. Каждый этап считывает данные с предыдущего этапа и передаёт результаты следующему через yield. Последний этап запускает конвейер, возобновляя последнюю корутину, после чего сигнал проходит каскадом обратно по цепочке.
local function source(items)
return coroutine.wrap(function()
for _, v in ipairs(items) do coroutine.yield(v) end
end)
end
local function filter(iter, pred)
return coroutine.wrap(function()
for v in iter do
if pred(v) then coroutine.yield(v) end
end
end)
end
local function map(iter, fn)
return coroutine.wrap(function()
for v in iter do coroutine.yield(fn(v)) end
end)
end
local pipeline = map(filter(source({1,2,3,4,5,6}),
function(n) return n%2==0 end),
function(n) return n*n end)
for v in pipeline do io.write(v.." ") end
print() -- 4 16 36Корутины для имитации асинхронности
Без потоков OS корутины могут имитировать асинхронные операции: выполняйте yield во время «ожидания» и возобновляйте корутину, когда «результат» готов. Планировщик возобновляет корутину, передавая ей результат.
local scheduler = {}
local current = nil
local function await(key)
coroutine.yield(key) -- tell scheduler what we need
return coroutine.yield() -- wait for result
end
local co = coroutine.create(function()
local data = await("fetch:users")
print("Got users:", data)
end)
-- Start coroutine
local ok, want = coroutine.resume(co)
print("Coroutine wants:", want) -- fetch:users
-- Simulate delivering the result:
coroutine.resume(co, {{name="Alice"},{name="Bob"}})yield внутри функции
Вы можете выполнить yield внутри любой функции, вызванной корутиной, а не только внутри функции верхнего уровня. yield проходит через все вложенные вызовы обратно к resume. Это называется «приостановленным стеком вызовов».
local function yieldTwice(label)
coroutine.yield(label .. ":1")
coroutine.yield(label .. ":2")
end
local co = coroutine.create(function()
yieldTwice("A")
yieldTwice("B")
end)
for i = 1, 4 do
local ok, v = coroutine.resume(co)
print(v)
end
-- A:1, A:2, B:1, B:2Корутины — не потоки
Корутины Lua — это не потоки OS. Одновременно выполняется только одна корутина; вытеснения и параллелизма нет. Все корутины используют один поток OS. Для настоящего параллелизма нужны несколько состояний Lua в отдельных потоках OS.
-- This is NOT parallel - interleaved execution
local function task(name, n)
for i = 1, n do
print(name, i)
coroutine.yield()
end
end
local t1 = coroutine.create(function() task("A", 3) end)
local t2 = coroutine.create(function() task("B", 3) end)
-- Must explicitly schedule:
for _ = 1, 3 do
coroutine.resume(t1)
coroutine.resume(t2)
end
-- A1, B1, A2, B2, A3, B3 (interleaved, NOT parallel)Состояние после возобновления
Проверяйте состояние корутины, чтобы определить, нужно ли возобновлять её снова. Корутина, завершившая работу (вернувшаяся из своей функции), находится в состоянии «завершена» — попытка возобновить её возвращает false и ошибку. Всегда проверяйте состояние перед возобновлением в циклах.
local co = coroutine.create(function()
for i = 1, 3 do coroutine.yield(i) end
end)
while coroutine.status(co) ~= "dead" do
local ok, val = coroutine.resume(co)
if ok and val ~= nil then
print("val:", val)
end
end
-- val: 1, val: 2, val: 3Несколько yield за одно возобновление
Один вызов coroutine.resume выполняет корутину до следующего yield или до её завершения. Нельзя заставить корутину выполнить yield несколько раз за одно возобновление: каждый yield приостанавливает её и ожидает следующего возобновления.
local co = coroutine.create(function()
local x = coroutine.yield("first")
print("got:", x)
local y = coroutine.yield("second")
print("got:", y)
end)
local _, v1 = coroutine.resume(co) -- starts, yields "first"
print("yielded:", v1) -- first
local _, v2 = coroutine.resume(co, "a") -- passes "a", yields "second"
print("yielded:", v2) -- second
coroutine.resume(co, "b") -- passes "b", coroutine endsБыстрая проверка
Во что превращаются значения, переданные в coroutine.yield(v1, v2)?
Итоги: resume и yield
Краткое содержание:
- Аргументы первого resume → параметры функции корутины
- Аргументы последующих resume → значения, возвращённые предыдущим yield()
- Аргументы yield → значения, возвращённые вызовом resume(), запустившим этот yield
- Двунаправленный обмен: каждый resume/yield — это обмен данными
- yield работает из любой вложенной функции
- Корутины работают кооперативно, а не параллельно
Часто задаваемые вопросы
Урок «resume и yield» бесплатный?
Да — полный текст урока «resume и yield» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Lua Academy, подпишись на CoddyKit PRO. Курс Lua Academy содержит 4 уроков всего.
Чему я научусь в уроке «resume и yield»?
Обменивайтесь данными между вызывающим кодом и сопрограммой с помощью resume/yield. Ты практикуешь Lua Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Lua Academy?
Предыдущий опыт не требуется. Lua Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «resume и yield»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Lua Academy?
Да. Каждый урок Lua Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.