web-dev-qa-db-fra.com

Une boucle d'événement asyncio peut-elle s'exécuter en arrière-plan sans suspendre l'interpréteur Python?

La documentation pour asyncio donne deux exemples pour imprimer "Hello World" toutes les deux secondes: https://docs.python.org/3/library/asyncio-eventloop.html#asyncio-hello-world-callbackhttps://docs.python.org/3/library/asyncio-task.html#asyncio-hello-world-coroutine

Je peux les exécuter à partir de l'interprète, mais si je le fais, je perds l'accès à l'interprète. Une boucle d'événement asyncio peut-elle être exécutée en arrière-plan, afin que je puisse continuer à taper des commandes sur l'interpréteur?

26

Vous pouvez exécuter la boucle d'événements à l'intérieur d'un thread d'arrière-plan:

>>> import asyncio
>>> 
>>> @asyncio.coroutine
... def greet_every_two_seconds():
...     while True:
...         print('Hello World')
...         yield from asyncio.sleep(2)
... 
>>> def loop_in_thread(loop):
...     asyncio.set_event_loop(loop)
...     loop.run_until_complete(greet_every_two_seconds())
... 
>>> 
>>> loop = asyncio.get_event_loop()
>>> import threading
>>> t = threading.Thread(target=loop_in_thread, args=(loop,))
>>> t.start()
Hello World
>>> 
>>> Hello World

Notez que vous devez appeler asyncio.set_event_loop sur le loop, sinon vous obtiendrez une erreur indiquant que le thread actuel n'a pas de boucle d'événement.

Si vous souhaitez interagir avec la boucle d'événements du thread principal, vous devrez vous en tenir à loop.call_soon_threadsafe appels.

Bien que ce genre de chose soit un bon moyen d'expérimenter dans l'interpréteur, dans les programmes réels, vous voudrez probablement tout votre code s'exécutant dans la boucle d'événements , plutôt que d'introduire des threads.

41
dano

Avec Python 3.8, vous pouvez utiliser le nouveau asyncio REPL.

$ python -m asyncio
>>> async def greet_every_two_seconds():
...     while True:
...         print('Hello World')
...         await from asyncio.sleep(2)
...
>>> # run in main thread (Ctrl+C to cancel)
>>> await greet_every_two_seconds()
...
>>> # run in background
>>> asyncio.create_task(greet_every_two_seconds())
2
zeronone