Lua
Сопрограммы
Поиск…
Синтаксис
coroutine.create (function) возвращает сопрограмму (type (coroutine) == 'thread'), содержащую эту функцию.
coroutine.resume (co, ...) возобновить или запустить сопрограмму. Любые дополнительные аргументы, возвращаемые резюме, возвращаются из coroutine.yield (), которые ранее приостановили сопрограмму. Если сопрограмма не была запущена, дополнительные аргументы становятся аргументами функции.
coroutine.yield (...) дает текущую исполняемую копию. Выполнение выполняет резервное копирование после вызова coroutine.resume (), который начал эту сопрограмму. Любые аргументы, даваемые уроку, возвращаются из соответствующей сопрограммы coroutine.resume (), которая запускает сопрограмму.
coroutine.status (co) возвращает статус сопрограммы, которая может быть:
- «dead»: функция в сопрограмме дошла до конца, и сопрограмма не может быть возобновлена больше
- «running»: сопрограмма продолжена и работает
- «normal»: сопрограмма возобновила другую сопрограмму
- «приостановлено»: сопротекция уступила и ждет возобновления
Функция coroutine.wrap (function) возвращает функцию, которая при вызове возобновляет сопрограмму, которая была бы создана командой coroutine.create (function).
замечания
Система coroutine была реализована в lua для эмуляции многопоточности, существующей на других языках. Он работает, переключаясь с чрезвычайно высокой скоростью между различными функциями, чтобы пользователь-пользователь считал, что они выполняются одновременно.
Создание и использование сопрограммы
Все функции для взаимодействия с сопрограммами доступны в таблице сопрограмм . Новая сопрограмма создается с помощью функции 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
Coroutines может приостановить его выполнение и возобновить его позже благодаря функции coroutine.yield :
thread2 = coroutine.create(function()
for n = 1, 5 do
print("honk "..n)
coroutine.yield()
end
end)
Как вы можете видеть, coroutine.yield () присутствует внутри цикла for, теперь, когда мы возобновляем сопрограмму coroutine, он будет выполнять код, пока не достигнет 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
Наконец, когда coroutine заканчивается, любые значения, возвращаемые его функцией, переходят к соответствующему резюме:
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
В этой функции используются Coroutines для передачи значений обратно в вызывающий поток из глубины рекурсивного вызова.
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}
Coroutines также может использоваться для ленивой оценки.
-- 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
Coroutines можно использовать для конструкций трубопроводов, как описано в « Программирование в Lua» . Автор PIL, Роберто Иерусульсамчий, также опубликовал статью об использовании сопрограмм для внедрения более совершенной и общей механики управления потоком, например продолжения.