Recherche…


Syntaxe

  • coroutine.create (function) renvoie une coroutine (type (coroutine) == 'thread') contenant la fonction.

  • coroutine.resume (co, ...) reprend ou démarre la coroutine. Tous les arguments supplémentaires donnés pour reprendre sont renvoyés par le coroutine.yield () qui a précédemment suspendu la coroutine. Si la coroutine n'a pas été démarrée, les arguments supplémentaires deviennent les arguments de la fonction.

  • coroutine.yield (...) donne la coroutine en cours d'exécution. L'exécution reprend après l'appel à coroutine.resume () qui a démarré cette coroutine. Tous les arguments donnés pour céder sont renvoyés par la coroutine.resume () correspondante qui a démarré la coroutine.

  • coroutine.status (co) renvoie le statut de la coroutine, qui peut être:

    • "mort": la fonction dans la coroutine a atteint sa fin et la coroutine ne peut plus être reprise
    • "running": la coroutine a repris et est en cours d'exécution
    • "normal": la coroutine a repris une autre coroutine
    • "suspendu": la coroutine a cédé et attend d'être reprise
  • coroutine.wrap (function) renvoie une fonction qui, lorsqu'elle est appelée, reprend la coroutine qui aurait été créée par coroutine.create (function).

Remarques

Le système de coroutine a été implémenté en lua pour émuler le multithreading existant dans d'autres langages. Cela fonctionne en commutant à une vitesse extrêmement élevée entre les différentes fonctions pour que l'utilisateur humain pense qu'elles sont exécutées en même temps.

Créer et utiliser une coroutine

Toutes les fonctions d'interaction avec les coroutines sont disponibles dans la table de coroutine . Une nouvelle coroutine est créée en utilisant la fonction coroutine.create avec un seul argument: une fonction avec le code à exécuter:

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

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

Un objet coroutine renvoie une valeur de type thread , représentant une nouvelle coroutine. Lorsqu'une nouvelle coroutine est créée, son état initial est suspendu:

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

Pour reprendre ou démarrer une coroutine, la fonction coroutine.resume est utilisée, le premier argument donné est l'objet thread:

coroutine.resume(thread1)
-->> honk

Maintenant, la coroutine exécute le code et se termine, changeant son état en mort , ce qui ne peut pas être repris.

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

Coroutines peut suspendre son exécution et la reprendre plus tard grâce à la fonction coroutine.yield :

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

Comme vous pouvez le voir, coroutine.yield () est présent dans la boucle for, maintenant, lorsque nous reprendrons la coroutine, il exécutera le code jusqu'à ce qu'il atteigne un coroutine.yield:

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

Une fois la boucle terminée, l'état du fil devient mort et ne peut plus être repris. Coroutines permet également l'échange entre les données:

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

Si la coroutine est à nouveau exécutée sans arguments supplémentaires, le complément sera toujours l'argument du premier résumé, dans ce cas "stackoverflow":

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

Enfin, quand une coroutine se termine, toutes les valeurs renvoyées par sa fonction vont au résumé correspondant:

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

Les coroutines sont utilisées dans cette fonction pour renvoyer des valeurs à un thread appelant depuis un appel récursif.

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}

Les coroutines peuvent également être utilisées pour une évaluation paresseuse.

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

Les coroutines peuvent être utilisées pour les constructions de tuyauterie comme décrit dans Programmation en Lua . L'auteur de PiL, Roberto Ierusalimschy, a également publié un article sur l'utilisation de coroutines pour mettre en œuvre des mécanismes de contrôle de flux plus avancés et généraux, comme les continuations.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow