Почему loop.run_forever() блокирует мой основной поток?

Во время обучения asyncio я пробовал этот код:

import asyncio
from  asyncio.coroutines import coroutine

@coroutine
def coro():
    counter: int = 0

    while True:
        print("Executed" + str(counter))
        counter += 1
        yield


 loop = asyncio.get_event_loop()
 loop.run_until_complete(coro())
 loop.run_forever()

 print("Finished!")

Я ожидал, что сопрограмма будет выполнена только один раз, потому что она содержит выход и должна была вернуть управление вызывающей стороне. Результат, который я ожидал, был:

Executed 0
Finished!

Я ожидал такого поведения, потому что думал, что цикл будет запускать сопрограмму навсегда, как только каждый "кадр" будет возвращаться вызывающей программе после каждого выполнения (что-то вроде фонового потока, но совместным образом). Но вместо этого он запускает сопрограмму навсегда, не возвращаясь? Вывод следующий:

Executed 0
Executed 1
Executed 2
Executed 3
...

Кто-нибудь может объяснить, почему это происходит вместо моих ожиданий?

Приветствия.

1 ответ

Решение

У вас есть пара проблем. Когда вы звоните run_until_complete, это ждет coro закончить, прежде чем перейти к вашему run_forever вызов. Как вы определили, coro никогда не заканчивается Он содержит бесконечный цикл, который не делает ничего, чтобы вырваться из цикла. Тебе необходимо break или return где-то внутри цикла, если вы хотите перейти к следующему шагу в вашем приложении.

Как только вы это сделаете, ваш следующий звонок run_forever, который, как следует из его названия, будет работать вечно. И в этом случае с этим ничего не поделаешь, потому что вы ничего не запланировали с помощью цикла обработки событий.

Я ожидал, что сопрограмма будет выполнена только один раз, потому что она содержит выход и должна была вернуть управление вызывающей стороне.

Если посмотреть на тот факт, что ваша сопрограмма не имеет выхода, ожидание (или уступка в зависимости от того, какой синтаксис вы выберете) не возвращает управление вызывающей стороне run_until_complete или же run_forever, Он возвращает управление в цикл обработки событий, так что он может проверять все, что ожидалось и готово возобновить.

Другие вопросы по тегам