Comment ajouter une nouvelle coroutine à une boucle asyncio en cours d'exécution? C'est à dire. celui qui exécute déjà un ensemble de coroutines.
Comme solution de contournement, on peut attendre que les coroutines existantes soient complètes, puis initialiser une nouvelle boucle (avec la coroutine supplémentaire). Mais y a-t-il une meilleure façon?
Vous pouvez utiliser create_task
pour planifier de nouvelles coroutines:
import asyncio
async def cor1():
...
async def cor2():
...
async def main(loop):
await asyncio.sleep(0)
t1 = loop.create_task(cor1())
await cor2()
await t1
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))
loop.close()
Votre question est très proche de "Comment ajouter un appel de fonction au programme en cours?"
Quand exactement devez-vous ajouter un nouveau coroutine à la boucle d'événement?
Voyons quelques exemples. Voici le programme qui démarre la boucle d’événement avec deux coroutines en parallèle:
import asyncio
from random import randint
async def coro1():
res = randint(0,3)
await asyncio.sleep(res)
print('coro1 finished with output {}'.format(res))
return res
async def main():
await asyncio.gather(
coro1(),
coro1()
) # here we have two coroutines running parallely
if __== "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Sortie:
coro1 finished with output 1
coro1 finished with output 2
[Finished in 2.2s]
Peut-être devrez-vous ajouter quelques coroutines qui prendraient les résultats de coro1
et les utiliser dès qu’il serait prêt? Dans ce cas, créez simplement une coroutine qui attend coro1
et utilisez sa valeur de retour:
import asyncio
from random import randint
async def coro1():
res = randint(0,3)
await asyncio.sleep(res)
print('coro1 finished with output {}'.format(res))
return res
async def coro2():
res = await coro1()
res = res * res
await asyncio.sleep(res)
print('coro2 finished with output {}'.format(res))
return res
async def main():
await asyncio.gather(
coro2(),
coro2()
) # here we have two coroutines running parallely
if __== "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Sortie:
coro1 finished with output 1
coro2 finished with output 1
coro1 finished with output 3
coro2 finished with output 9
[Finished in 12.2s]
Pensez aux coroutines comme aux fonctions régulières avec une syntaxe spécifique. Vous pouvez démarrer un ensemble de fonctions à exécuter en parallèle (avec asyncio.gather
), vous pouvez lancer la fonction suivante après la première utilisation, vous pouvez créer de nouvelles fonctions qui appellent d’autres.
Aucune des réponses ici ne semble répondre exactement à la question. Il est possible d’ajouter des tâches à une boucle d’événement en cours d’exécution en faisant effectuer une tâche "parent" à votre place. Je ne sais pas quel est le moyen le plus pythonique de s’assurer que ce parent ne se termine pas tant que ses enfants n’ont pas tous fini (en supposant que ce soit le comportement souhaité), mais cela fonctionne.
import asyncio
import random
async def add_event(n):
print('starting ' + str(n))
await asyncio.sleep(n)
print('ending ' + str(n))
return n
async def main(loop):
added_tasks = []
delays = [x for x in range(5)]
# shuffle to simulate unknown run times
random.shuffle(delays)
for n in delays:
print('adding ' + str(n))
task = loop.create_task(add_event(n))
added_tasks.append(task)
await asyncio.sleep(0)
print('done adding tasks')
# make a list of tasks that (maybe) haven't completed
running_tasks = added_tasks[::]
# wait until we see that all tasks have completed
while running_tasks:
running_tasks = [x for x in running_tasks if not x.done()]
await asyncio.sleep(0)
print('done running tasks')
# extract the results from the tasks and return them
results = [x.result() for x in added_tasks]
return results
loop = asyncio.get_event_loop()
results = loop.run_until_complete(main(loop))
loop.close()
print(results)