Ricerca…


Sintassi

  • coroutine.create (funzione) restituisce una coroutine (tipo (coroutine) == 'thread') contenente la funzione.

  • coroutine.resume (co, ...) riprendi o avvia la coroutine. Qualsiasi argomento addizionale dato per riprendere viene restituito dal coroutine.yield () che precedentemente ha sospeso la coroutine. Se non è stata avviata la coroutine, gli argomenti aggiuntivi diventano gli argomenti della funzione.

  • coroutine.yield (...) restituisce la coroutine attualmente in esecuzione. L'esecuzione riprende dopo la chiamata a coroutine.resume () che ha avviato quella coroutine. Qualsiasi argomento fornito per la resa viene restituito dalla corrispondente coroutine.resume () che ha avviato la coroutine.

  • coroutine.status (co) restituisce lo stato della coroutine, che può essere:

    • "dead": la funzione nella coroutine ha raggiunto la sua fine e la coroutine non può più essere ripresa
    • "in esecuzione": la coroutine è stata ripresa ed è in esecuzione
    • "normale": la coroutine ha ripreso un'altra coroutine
    • "sospeso": la coroutine ha ceduto ed è in attesa di ripresa
  • coroutine.wrap (funzione) restituisce una funzione che quando viene richiamata riprende la coroutine che sarebbe stata creata da coroutine.create (funzione).

Osservazioni

Il sistema di coroutine è stato implementato in lua per emulare il multithreading esistente in altre lingue. Funziona passando ad una velocità estremamente alta tra le diverse funzioni in modo che l'utente umano pensi di essere eseguito nello stesso momento.

Crea e usa una coroutine

Tutte le funzioni per interagire con le coroutine sono disponibili nella tabella delle coroutine . Viene creata una nuova coroutine utilizzando la funzione coroutine.create con un singolo argomento: una funzione con il codice da eseguire:

thread1 = coroutine.create(function()
            print("honk")
        end)

print(thread1)
-->> thread: 6b028b8c

Un oggetto di coroutine restituisce il valore di tipo thread , che rappresenta una nuova coroutine. Quando viene creata una nuova coroutine, il suo stato iniziale viene sospeso:

print(coroutine.status(thread1))
-->> suspended

Per riprendere o avviare una coroutine, viene utilizzata la funzione coroutine.resume , il primo argomento fornito è l'oggetto thread:

coroutine.resume(thread1)
-->> honk

Ora la coroutine esegue il codice e termina, cambiando il suo stato in dead , che non può essere ripreso.

print(coroutine.status(thread1))
-->> dead

Coroutine possono sospendere la sua esecuzione e riprenderla in seguito grazie alla funzione coroutine.yield :

thread2 = coroutine.create(function()
        for n = 1, 5 do
            print("honk "..n)
            coroutine.yield()
        end
    end)

Come puoi vedere, coroutine.yield () è presente all'interno del ciclo for, ora quando riprendiamo la coroutine, eseguirà il codice fino a raggiungere una coroutine.yield:

coroutine.resume(thread2)
-->> honk 1
coroutine.resume(thread2)
-->> honk 2

Dopo aver terminato il ciclo, lo stato del thread diventa morto e non può essere ripreso. Coroutine consente anche lo scambio tra i dati:

thread3 = coroutine.create(function(complement)
    print("honk "..complement)
    coroutine.yield()
    print("honk again "..complement)
end)
coroutine.resume(thread3, "stackoverflow")
-->> honk stackoverflow

Se la coroutine viene eseguita di nuovo senza argomenti aggiuntivi, il complemento rimarrà comunque l'argomento dal primo curriculum, in questo caso "stackoverflow":

coroutine.resume(thread3)
-->> honk again stackoverflow

Infine, quando termina una coroutine, qualsiasi valore restituito dalla sua funzione va al curriculum corrispondente:

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

Le Coroutine vengono utilizzate in questa funzione per trasferire i valori a un thread chiamante da una chiamata ricorsiva profonda.

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}

Le coroutine possono anche essere usate per la valutazione pigra.

-- 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

Le coroutine possono essere utilizzate per i costrutti di tubazioni come descritto in Programmazione in Lua . L'autore di PiL, Roberto Ierusalimschy, ha anche pubblicato un articolo sull'uso delle coroutine per implementare meccanismi di controllo del flusso più avanzati e generali come le continuazioni.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow