Почему loop.run_forever () блокирует мой основной поток? - PullRequest
0 голосов
/ 26 апреля 2018

Во время обучения 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 Ответ

0 голосов
/ 26 апреля 2018

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

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

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

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

...