Les coroutines

⚠️ Les bases du langage doivent être bien maîtrisées avant d’aborder cette section. N’hésitez pas à relire plusieurs fois.

N’utilisez les coroutines que si vous savez ce que vous faites !

Les coroutines en Lua sont comparables aux threads en C, à une différence près :
plusieurs coroutines peuvent être créées, mais une seule peut s’exécuter à la fois. Lorsqu’une coroutine est active, elle bloque l’exécution du programme principal jusqu’à ce qu’elle rende la main.

Utilisation simple

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function f()
  print("Bonjour")
end

co = coroutine.create(f)
print(co)
coroutine.resume(co)

-- output :
--  thread: 0x64
--  Bonjour

Avec fonction anonyme

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
local co = coroutine.create(function()
  print("Bonjour")
end)

print(co)
coroutine.resume(co)

-- output :
--  thread: 0xa8
--  Bonjour

Coroutine bloquante

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
function f()
  print("Début de la coroutine")
  local t0 = os.clock()
  while os.clock() - t0 <= 5 do end
  print("Fin de la coroutine")
end

co = coroutine.create(f)
coroutine.resume(co)
print("Fin du programme")

-- output :
--  Début de la coroutine
--  Fin de la coroutine (après 5s)
--  Fin du programme

États des coroutines

Utilisez coroutine.status() pour vérifier l’état d’une coroutine :

État Signification
suspended En pause
running En cours d’exécution
dead Terminée

Une coroutine dead ne peut plus être redémarrée.

coroutine.yield() : mise en pause

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function f()
  for i = 0, 2 do
    print(i)
    coroutine.yield()
  end
end

co = coroutine.create(f)
coroutine.resume(co)
coroutine.resume(co)
coroutine.resume(co)

print(coroutine.status(co))
coroutine.resume(co)
print(coroutine.status(co))
coroutine.resume(co)  -- Erreur : coroutine morte

-- output :
--  0
--  1
--  2
--  suspended
--  dead
--  cannot resume dead coroutine

Générateurs avec paramètres

1
2
3
4
5
6
7
8
9
function somme(a, b)
  coroutine.yield(a + b)
end

co = coroutine.create(somme)
print(coroutine.resume(co, 6, 4))

-- output :
--  true    10

Itérateurs

Les coroutines peuvent être utilisées pour créer des itérateurs simples :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
function f()
  local tab = {1, 2, 3, 4, 5}
  for i = 1, #tab do
    coroutine.yield(tab[i])
  end
end

co = coroutine.create(f)
while true do
  local code, res = coroutine.resume(co)
  if not code then break end
  print(res)
end

-- output :
--  1
--  2
--  3
--  4
--  5

Ces exemples sont volontairement simples. Les coroutines permettent bien d’autres usages, que nous aborderons dans des tutoriels plus avancés.