TLDR: Нет. Только сопрограммы и соответствующие им ключевые слова (await
, async with
, async for
) включить приостановка. То, произойдет ли приостановка, зависит от используемой структуры, если вообще.
Сторонние асинхронные c функции / итераторы / контекстные менеджеры могут выступать в качестве контрольных точек; если вы видите await <something>
или одного из его друзей, то это может быть контрольно-пропускной пункт. Поэтому, чтобы быть в безопасности, вы должны подготовиться к планированию или отмене, происходящим там.
[ Документация Trio ]
Синтаксис await
Python является синтактическим c сахаром вокруг двух основных механизмов: yield
до временно приостанавливает со значением и return
до навсегда завершает со значением. Это то же самое, что, скажем, функция сопрограммы генератора может использовать:
def gencoroutine():
for i in range(5):
yield i # temporarily suspend
return 5 # permanently exit
Примечательно, что return
не не подразумевает приостановку. Возможно, что сопрограмма генератора вообще никогда не будет yield
.
Ключевое слово await
(и его родной элемент yield from
) взаимодействует с обоими механизмами yield
и return
:
- Если его цель
yield
s, await
"передает" приостановку своему вызывающему абоненту. Это позволяет приостановить весь стек сопрограмм, чтобы все await
друг друга. - Если его цель
returns
s, await
перехватывает возвращаемое значение и предоставляет его собственному сопрограммная. Это позволяет возвращать значение непосредственно «вызывающему» без приостановки.
Это означает, что await
не не гарантирует, что приостановка произошла. Задача await
может вызвать приостановку.
Сама по себе async def
сопрограмма может только return
без приостановки и await
до разрешить приостановку. Он не может приостановиться сам по себе (yield
не приостанавливается на событие l oop).
async def unyielding():
return 2 # or `pass`
Это означает, что await
из только сопрограмм делает никогда приостановить . Только определенные c ожидающие могут приостановить.
Приостановка возможна только для ожидающих с пользовательским __await__
методом. Они могут yield
непосредственно к событию l oop.
class YieldToLoop:
def __await__(self):
yield # to event loop
return # to awaiter
Это означает, что await
, прямо или косвенно, ожидаемого фреймворка, приостановит .
Точная семантика приостановки зависит от используемой платформы asyn c. Например, sleep(0)
вызывает приостановку или нет, или какую сопрограмму вместо этого запустить, зависит от структуры. Это также распространяется на асинхронные c итераторы и контекстные менеджеры - например, многие асинхронные c контекстные менеджеры будут приостанавливать либо при входе или выходе, но не при обоих.
Trio
Если вы вызываете асинхронную функцию c, предоставляемую Trio (await <something in trio>
), и она не вызывает исключение, то она всегда действует как контрольная точка. (Если оно вызывает исключение, оно может действовать как контрольная точка или нет.)
Asyncio
sleep()
всегда приостанавливает текущую задачу, разрешая другие задачи бежать.