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.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow