Что вызывает ошибку?
Проблема с использованием asyncio.all_tasks()
заключается в том, что он возвращает ВСЕ задачи, даже те, которые вы не создавали напрямую. Измените свой код следующим образом, чтобы увидеть, что вы отменяете:
for task in tasks:
print(task)
task.cancel()
Вы увидите не только worker
связанных задач, но также:
<Task pending coro=<main() running at ...>
Отмена main
приводит к беспорядок внутри asyncio.run(main())
и вы получите ошибку. Давайте сделаем быструю / грязную модификацию, чтобы исключить эту задачу из отмены:
tasks = [
t
for t
in asyncio.all_tasks()
if (
t is not asyncio.current_task()
and t._coro.__name__ != 'main'
)
]
for task in tasks:
print(task)
task.cancel()
Теперь вы увидите, что results
.
l oop .stop () приводит к ошибке
Пока вы набрали results
, вы получите еще одну ошибку Event loop stopped before Future completed
. Это происходит потому, что asyncio.run(main())
хотят работать до завершения main()
.
Вы должны реструктурировать свой код, чтобы разрешить выполнение сопрограммы, переданной вами в asyncio.run
, вместо остановки события l oop или, например, , используйте l oop .run_forever () вместо asyncio.run
.
Вот быстрая / грязная демонстрация того, что я имею в виду:
async def shutdown(loop):
# ...
global _stopping
_stopping = True
# loop.stop()
_stopping = False
async def main():
# ...
while not _stopping:
await queue.put('tick')
await asyncio.sleep(1)
Теперь ваш код будет работать без ошибок. Не используйте приведенный выше код на практике, это всего лишь пример. Попробуйте реструктурировать свой код, как я упоминал выше.
Как правильно обрабатывать задачи
Не использовать asyncio.all_tasks()
.
Если вы создаете некоторые задачи, которые вы хотите отменить в будущем, сохраните их и отмените только сохраненные задачи. Псевдокод:
i_created = []
# ...
task = asyncio.create_task(worker())
i_created.append(task)
# ...
for task in i_created:
task.cancel()
Может показаться неудобным, но это способ убедиться, что вы не отменяете то, что не хотите отменять.
Еще одна вещь
Обратите также внимание, что asyncio.run()
делает намного больше , чем просто начало события l oop. В частности, отменяет все зависающие задачи перед завершением. В некоторых случаях это может быть полезно, хотя я советую вместо этого обрабатывать все отмены вручную.