Szukaj…
Składnia
coroutine.create (funkcja) zwraca coroutine (typ (coroutine) == 'thread') zawierający funkcję.
coroutine.resume (co, ...) wznawia lub uruchamia coroutine. Wszelkie dodatkowe argumenty podane w celu wznowienia są zwracane z coroutine.yield (), który wcześniej wstrzymywał coroutine. Jeśli coroutine nie został uruchomiony, dodatkowe argumenty stają się argumentami funkcji.
coroutine.yield (...) daje aktualnie działającą coroutine. Wykonanie wznawia działanie po wywołaniu coroutine.resume (), które uruchomiło tę coroutine. Wszelkie argumenty podane dla wydajności są zwracane z odpowiedniego coroutine.resume (), który uruchomił coroutine.
coroutine.status (co) zwraca status coroutine, który może być:
- „martwy”: funkcja w rogówce osiągnęła swój koniec i nie można już wznowić rogówki
- „running”: coroutine zostało wznowione i działa
- „normalny”: koruta wznowiła kolejną koroutynę
- „zawieszony”: coroutine ustąpił i czeka na wznowienie
coroutine.wrap (funkcja) zwraca funkcję, która po wywołaniu wznawia coroutine, która zostałaby utworzona przez coroutine.create (funkcja).
Uwagi
System coroutine został wdrożony w lua w celu emulacji wielowątkowości istniejącej w innych językach. Działa poprzez przełączanie z bardzo dużą prędkością między różnymi funkcjami, tak aby użytkownik mógł myśleć, że są one wykonywane jednocześnie.
Stwórz i użyj coroutine
Wszystkie funkcje do interakcji z coroutines są dostępne w tabeli coroutine . Nowa coroutine jest tworzona za pomocą funkcji coroutine.create z jednym argumentem: funkcja z kodem do wykonania:
thread1 = coroutine.create(function()
print("honk")
end)
print(thread1)
-->> thread: 6b028b8c
Obiekt coroutine zwraca wartość typu wątek , reprezentujący nową coroutine. Gdy tworzona jest nowa coroutine, jej stan początkowy jest zawieszony:
print(coroutine.status(thread1))
-->> suspended
Aby wznowić lub uruchomić coroutine, używana jest funkcja coroutine.resume , pierwszym podanym argumentem jest obiekt wątku:
coroutine.resume(thread1)
-->> honk
Teraz coroutine wykonuje kod i kończy działanie, zmieniając swój stan na martwy , którego nie można wznowić.
print(coroutine.status(thread1))
-->> dead
Coroutines może zawiesić jego wykonanie i wznowić go później dzięki funkcji coroutine.yield :
thread2 = coroutine.create(function()
for n = 1, 5 do
print("honk "..n)
coroutine.yield()
end
end)
Jak widać, coroutine.yield () jest obecny w pętli for, teraz, kiedy wznawiamy coroutine, będzie on wykonywał kod, dopóki nie osiągnie coroutine.yield:
coroutine.resume(thread2)
-->> honk 1
coroutine.resume(thread2)
-->> honk 2
Po zakończeniu pętli status wątku jest martwy i nie można go wznowić. Coroutines umożliwia także wymianę danych:
thread3 = coroutine.create(function(complement)
print("honk "..complement)
coroutine.yield()
print("honk again "..complement)
end)
coroutine.resume(thread3, "stackoverflow")
-->> honk stackoverflow
Jeśli coroutine zostanie ponownie wykonany bez dodatkowych argumentów, dopełniacz nadal będzie argumentem z pierwszego wznowienia, w tym przypadku „stackoverflow”:
coroutine.resume(thread3)
-->> honk again stackoverflow
Wreszcie po zakończeniu coroutine wszystkie wartości zwrócone przez jego funkcję przechodzą do odpowiedniego CV:
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
W tej funkcji używane są coroutines, aby przekazywać wartości z powrotem do wątku wywołującego z głębi wywołania rekurencyjnego.
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}
Korupiny mogą być również używane do leniwej oceny.
-- 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
Korupiny można stosować do konstruowania rurociągów, jak opisano w Programowaniu w Lua . Autor PiL, Roberto Ierusalimschy, opublikował także artykuł na temat stosowania coroutines do wdrażania bardziej zaawansowanych i ogólnych mechanizmów kontroli przepływu, takich jak kontynuacje.