coroutine :
- c'est une version spécialisée d'une fonction ou d'un generator qui peut suspendre son exécution avant d'atteindre le return ou le yield (permettant au programme de faire autre chose pendant ce temps).
- on la déclare avec async def myFunc1(...)
- elle peut contenir un await myFunc2(...) : ça va suspendre temporairement l'exécution de myFunc1 et faire autre chose jusqu'à ce que le résultat de myFunc2 soit disponible.
- une fonction déclarée avec async peut utiliser await, return et/ou yield.
- pour appeler une fonction async, il faut l'appeler avec await myFunc1(...), et on ne peu le faire qu'à l'intérier d'une fonction async.
Fonctions disponibles :
- asyncio.sleep(2) : coroutine qui ne fait rien (ici pendant 2 secondes).
- asyncio.run(f()) : prend le contrôle de l'event loop dans une fonction classique et exécute la coroutine f.
Différentes façons d'appeler une coroutine myFunc :
- l'appeler avec await (qui est donc contenu à l'intérieur d'une fonction async) : await myFunc(arg1, arg2, ...)
- l'appeler comme une task, ce qui permet d'exécuter plusieurs tâches en parallèle (dans une fonction async) : myTask = asyncio.create_task(myFunc(arg1, arg2, ...)); ...; await myTask
- l'appeler avec asyncio.run() : asyncio.run(myFunc(arg1, arg2, ...)) (appel dans une fonction classique)
- attention : l'appel direct de myFunc (sans await) n'appelle pas la fonction (et fait un warning) !
Exemple d'appel avec des tasks :
- les 2 tasks tournent de manière concurrente :
myTask1 = asyncio.create_task(myFunc1(...))
myTask2 = asyncio.create_task(myFunc2(...))
...
await myTask1
await myTask2
- autre façon (le lancement est implicite) :
async with asyncio.TaskGroup() as tg:
myTask1 = tg.create_task(myFunc1(...))
myTask2 = tg.create_task(myFunc2(...))
asyncio.gather : coroutine qui appelle les coroutines qu'on lui donne pour les exécuter de manière concurrente et retourne la liste des résultats de chaque coroutine une fois que tous les appels sont terminés : result = asyncio.gather(myFunc1(...), myFunc2())
asyncio.timeout : context manager qui peut être utilisé pour limiter le temps passé à exécuter une coroutine :
try:
async with asyncio.timeout(10):
await myFunc(...)
except TimeoutError:
print('trop long')
si la tâche a pris plus de 10 secondes, déclenche une erreur TimeoutError
asyncio.to_thread :
def someFunc(x, y):
time.sleep(2)
print(x + y)
async def myFunc():
await asyncio.sleep(1)
async def main():
# les arguments 3 et 4 sont passés à la fonction.
await async.gather(myFunc(), async.to_thread(someFunc, 3, 4))