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 laroutine
ou des données injecter dans lapause
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 lapause
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
oudead
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 lespause
Retour
-
args
un ensemble d'argument associer aux des données injecter dans lapause
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
- Roberto Ierusalimschy, « 9.1 – Coroutine Basics », lua.org, https://www.lua.org/pil/9.1.html
- Inconnu, « Lua - Coroutines », www.tutorialspoint.com, https://www.tutorialspoint.com/lua/lua_coroutines.htm
- Sylvain Fabre et al., Le guide de lua et ses applications : Manuel d'apprentissage, D-Booker, 04/2016, pages 65-67.
Commentaires1
Salut Léo, ton article sur…
Salut Léo, ton article sur les coroutines en Lua est vraiment bien ficelé ! J'apprécie particulièrement la façon dont tu as structuré l'information pour la rendre accessible, même pour quelqu'un qui débute avec ce concept. Ta présentation des coroutines comme étant monothread et asymétriques est un point fort. Ça aide vraiment à comprendre pourquoi on parle de "stratégie de coroutine" plutôt que de multitâche concurrent. Bien joué ! J'ai trouvé très utile ton explication détaillée des fonctions de la bibliothèque coroutine, avec des exemples concrets à l'appui. Ça rend le tout beaucoup plus tangible. Ce que j'ai particulièrement apprécié : Ta distinction claire entre coroutines et threads classiques. Ça évite pas mal de confusions ! Tes exemples de code sont limpides et illustrent parfaitement le fonctionnement de chaque fonction. J'ai adoré la partie sur les cas d'utilisation concrets (animations, IA, requêtes asynchrones). Ça donne vraiment envie d'essayer ! Bref, c'est un super article qui m'a permis de mieux saisir l'intérêt et le fonctionnement des coroutines en Lua. Merci pour ce travail de qualité, Léo !