Когда Python прекратит выполнение сопрограммы? - PullRequest
3 голосов
/ 19 мая 2019

Когда я запускаю его на cpython 3.6, следующая программа печатает hello world один раз, а затем вращается вечно.

В качестве примечания, если раскомментировать строку await asyncio.sleep(0), она напечатает hello worldкаждую секунду, что понятно.

import asyncio

async def do_nothing():
    # await asyncio.sleep(0)
    pass

async def hog_the_event_loop():
    while True:
        await do_nothing()

async def timer_print():
    while True:
        print("hello world")
        await asyncio.sleep(1)

loop = asyncio.get_event_loop()
loop.create_task(timer_print())
loop.create_task(hog_the_event_loop())
loop.run_forever()

Такое поведение (печать hello world один раз) имеет смысл для меня, потому что hog_the_event_loop никогда не блокирует и, следовательно, не нуждается в приостановке выполнения. Могу ли я рассчитывать на это поведение? Когда работает строка await do_nothing(), возможно ли, что вместо ввода сопрограммы do_nothing() выполнение будет фактически приостановлено и возобновится timer_print(), что приведет к печати программы hello world во второй раз?

В целом: когда python приостановит выполнение сопрограммы и переключится на другую?Возможно ли любое использование ключевого слова await?или это только в тех случаях, когда это приводит к базовому select вызову (например, ввод-вывод, таймеры отключения и т. д.)?

Дополнительное уточнение

Я понимаю, что если hog_the_event_loopВыглядело это так, что, безусловно, никогда не приведет к выполнению другой сопрограммы:

async def hog_the_event_loop():
    while True:
        pass

Я пытаюсь конкретно задать вопрос о том, отличается ли await do_nothing() от вышеуказанного.

Ответы [ 2 ]

2 голосов
/ 19 мая 2019

Такое поведение (однократная печать мира приветствия) имеет смысл для меня, потому что hog_the_event_loop никогда не блокирует и, следовательно, нет необходимости приостанавливать выполнение. Можно ли рассчитывать на это поведение?

Да. Это поведение напрямую следует из того, как await определяется и реализуется языком. Изменение его на приостановку без приостановки ожидаемого объекта, безусловно, будет серьезным изменением, как для asyncio , так и для других библиотек Python, основанных на async / await.

В целом: когда python приостановит выполнение сопрограммы и переключится на другую? Возможно ли использование ключевого слова await?

С точки зрения вызывающего абонента любой await может потенциально приостановить по усмотрению ожидаемого объекта, также известного как awaitable . Таким образом, окончательное решение о том, будет ли конкретный await приостановлен, принимается ожидаемым (или ожидаемым - оно ожидает себя, если оно является сопрограммой и т. Д.). Ожидание ожидающего, который не выбирает приостановку, аналогично выполнению обычного кода Python - оно не передаст управление циклу событий.

Конечные ожидающие ожидания, которые фактически приостанавливаются, обычно связаны с готовностью ввода-вывода или событиями тайм-аута, но не всегда. Например, ожидание элемента queue будет приостановлено, если очередь пуста, и ожидание run_in_executor будет приостановлено до завершения функции, выполняющейся в другом потоке.

Стоит отметить, что asyncio.sleep означает явно гарантированное приостановить выполнение и отложить на цикл обработки событий, даже если указанная задержка равна 0 (в этом случае он немедленно возобновится в следующем цикле обработки событий). проходят).

1 голос
/ 19 мая 2019

Нет, await do_nothing() никогда не приостановится.await размножает суспензию от ожидаемого путем приостановки окружающего сопрограмма в ответ.Но когда ожидаемое уже готово, ждать нечего, и выполнение продолжается с await (с возвращаемым значением, в общем).

Сопрограмма, которая ничего не делает, всегда готова, как та, котораяСпит готов по истечении времени.Иными словами, сопрограмма, которая просто спит N раз, приостанавливает N раз - даже если N равно 0.

...