Skip to content

Instantly share code, notes, and snippets.

@Finnwinch
Created February 9, 2025 13:26
Show Gist options
  • Save Finnwinch/f73d4ea0c9ebc472f5e112e0d888f3d2 to your computer and use it in GitHub Desktop.
Save Finnwinch/f73d4ea0c9ebc472f5e112e0d888f3d2 to your computer and use it in GitHub Desktop.
co lua

Stratégie de Coroutines en Lua

Pourquoi parler de stratégie de coroutine et non de coroutine en Lua ?

La raison principale est que le concept réel de coroutine n’existe pas tout à fait en Lua. En effet, les coroutines en Lua sont monothread, autrement dit asymétriques.

Contrairement aux threads traditionnels, qui permettent une exécution parallèle, les coroutines en Lua fonctionnent dans un seul thread et exigent une gestion explicite du passage de contrôle. Cela signifie qu’une coroutine ne reprend son exécution que lorsqu’elle est explicitement réactivée par l’appelant via coroutine.resume(). Inversement, une coroutine suspend son exécution volontairement en appelant coroutine.yield().

Une gestion explicite du passage de contrôle

L’utilisation des coroutines repose donc sur une stratégie bien définie pour organiser la coopération entre différentes parties du programme. Par exemple, elles sont souvent employées pour :

  • Implémenter des itérateurs
  • Mettre en place des systèmes de gestion d’événements
  • Créer des mécanismes de planification de tâches non bloquantes style une requête web asynchrone

Stratégie d’utilisation des coroutines

Une bonne stratégie d’utilisation des coroutines en Lua implique de structurer son code de manière à minimiser les points de blocage et à garantir une reprise fluide de l’exécution. Par exemple, dans un jeu vidéo, les coroutines peuvent être utilisées pour gérer :

  • Des animations
  • Des comportements d’intelligence artificielle

Cela permet d’éviter de bloquer le fil principal d’exécution.

Simuler de la concurrence

Bien que Lua n’offre pas de multitraitement natif, il est possible de combiner les coroutines avec des bibliothèques externes ou des threads en C pour simuler une exécution concurrente. Cependant, cela demande une gestion soigneuse des ressources partagées et une coordination efficace entre les différents processus en cours d’exécution.

La bibliothèque coroutine permet de créer, démarrer et suivre des routines dans le cadre de la gestion de l’exécution concurrente en Lua.

1. coroutine.create(function : Function)

Description

Cette fonction permet de créer une routine à partir d’une fonction.
Une routine représente une séquence d’exécution qui peut être mise en pause et reprise.

Paramètres

  • function : Une fonction Lua qui contient le code à exécuter dans la routine.

Retour

  • Retourne un objet Routine qui représente la routine créée.

Example

local routine = coroutine.create(function()
    print("Cette routine est exécutée !")
end)

2. coroutine.resume(routine:Routine,args:...?)

Description

Cette fonction permet d’executé une routine

Paramètres

  • routine : la routine à exécuter
  • args : un ensemble d’argument associer à la fonction dans la routine ou des données injecter dans la pause précédent

Retours

  • Succès d’éxécution de la routine
  • Message d’erreur de la routine (falcultatif)
  • args un ensemble d’argument associer aux des données injecter dans la pause précédent (falcultatif)

Example simple

local routine = coroutine.create(function(qui,message)
    print(qui,message)
end)
Coroutine.resume(routine,"Yoda","Bonjour  maître Yoda")
Yoda    Bonjour  maître Yoda

Example avec une erreur

local routine = coroutine.create(function(qui,message)
    print(qui,message)
end)
coroutine.resume(routine,"Yoda","Bonjour maître Yoda")
local estBienExecuter, messageErreur = coroutine.resume(routine)
print(estBienExecuter, messageErreur)
Yoda    Bonjour maître Yoda
false   cannot resume dead coroutine

3.coroutine.status(routine:Routine)

Description

Permet d’obtenir le status de la Routine

  • suspended : la routine est disponible, mais non utilisé
  • running : la routine est en cours d’exécution
  • normal : lorsque la routine est lancer par une autre
  • dead : la routine est morte

Paramètres

  • Routine : la routine à exécuter

Retour

  • Status : suspended, running ou dead

Examples de cycle de vie d’une routine

local status = {
    avant = nil,
    pendant = nil,
    apres = nil
}
local routine, bienvenue
bienvenue = function(nom)
    print("Bonjour",nom)
    status.pendant = coroutine.status(routine)
end
routine = coroutine.create(bienvenue)
status.avant = coroutine.status(routine)
coroutine.resume(routine,"Léo")
status.apres = coroutine.status(routine)
for etape,etat in pairs(status) do print(etape,etat) end
Bonjour Léo
avant   suspended
pendant running
apres   dead

4. coroutine.yield(args:...?)

Description

Permet de mettre en pause une routine pour son prochain apelle.
Permet l'échapement et l'injection de données vers une Routine

Paramètres

args : un ensemble d’argument associer à la fonction dans les pareméetre de yield pour l'éhcapement et comme assignation pour l'injection(falcultatif)w

Retour

args : un ensemble d’argument associer à la fonction dans les pareméetre de yield pour l'éhcapement (falcultatif)
pause de la routine

Conseil

pour savoir le nombre de coroutine.resume à faire. compter le nombre de coroutine.yield + 1 dans votre fonction.

Example échapement

local routine = coroutine.create(function()
    coroutine.yield("données échaper")
end)
local estExecuter, donneExtrapoler = coroutine.resume(routine)
print(donneExtrapoler)
données échaper

Example injection

local routine = coroutine.create(function()
    local x = coroutine.yield()
    print(x)
end)
coroutine.resume(routine)
coroutine.resume(routine,"Données injecter")
Données injecter

5. coroutine.wrap(function:Function)

Description

Permet de créer une fonction avec un comportement de routine sans être une routine

Paramètres

  • Fonction : la fonction avec les pause

Retour

  • args un ensemble d’argument associer aux des données injecter dans la pause précédent (falcultatif)

Example

routine = coroutine.wrap(function()
    print("Étape 1")
    local reponse = coroutine.yield("Bonjour maître Yoda")
    print("Étape 2 - "..reponse)
    coroutine.yield()
    print("Étape 3")
end)
local data = routine()
print(data)
routine("Bonjour Luc")
routine()
Étape 1
Bonjour maître Yoda
Étape 2 - Bonjour Luc
Étape 3

6. coroutine.close(routine:Routine)

Description

permet de tuer votre routine

Paramètres

  • Routine : la routine à tuer

Retour

  • boolean : true si la routine existe

Example

local routine = coroutine.create(function()
    print("Dans la coroutine, c'est :", 
        coroutine.running()-- Affiche l'ID de la coroutine
    )
end)
coroutine.close(routine)
print(coroutine.resume(routine))
false   cannot resume dead coroutine

Références

@TheObtey
Copy link

Finnwinch my beloved ♥

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment