Подтвердить что ты не робот

Асинхронные методы Python - как они работают?

У меня возникли проблемы с пониманием использования асинхронных понятий, представленных в Python 3.6. Как отказ от ответственности, у меня нет большого опыта работы с асинхронным кодом вообще в Python.

Пример, приведенный в для нового документа Python 3.6:

result = [i async for i in aiter() if i % 2]

В PEP это расширено:

result = []
async for i in aiter():
    if i % 2:
        result.append(i)

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

То, что я не уверен, так это то, что затем переводит на понимание списка здесь. Устанавливаются ли результаты в список в том порядке, в котором они возвращаются? Или есть эффективные "заполнители" в конечном списке, чтобы каждый результат был помещен в список в правильном порядке? Или я думаю об этом неправильно?

Кроме того, кто-то может предоставить пример в реальном мире, который иллюстрирует как применимый пример использования, так и основную механику async в таких выражениях?

4b9b3361

Ответ 1

В основном вы спрашиваете, как цикл async for работает над регулярным циклом. То, что вы теперь можете использовать такой цикл в понимании списка, здесь не имеет никакого значения; что просто оптимизация, которая позволяет избежать повторных вызовов list.append(), точно так же, как и в обычном понимании списка.

Затем цикл async for просто ждет каждый следующий шаг протокола итерации, где будет блокироваться обычный цикл for.

Чтобы проиллюстрировать, представьте обычный цикл for:

for foo in bar:
    ...

Для этого цикла Python по существу делает это:

bar_iter = iter(bar)
while True:
    try:
        foo = next(bar_iter)
    except StopIteration:
        break
    ...

Вызов next(bar_iter) не является асинхронным; он блокирует.

Теперь замените for на async for, и что делает Python:

bar_iter = aiter(bar)  # aiter doesn't exist, but see below
while True:
    try:
        foo = await anext(bar_iter)  # anext doesn't exist, but see below
    except StopIteration:
        break
    ...

В приведенном выше примере aiter() и anext() являются вымышленными функциями; это функционально точные эквиваленты их браков iter() и next(), но вместо __iter__ и __next__ они используют __aiter__ и __anext__. То есть, асинхронные крючки существуют для одной и той же функциональности, но отличаются от их неасинхронных вариантов префиксом a.

В ключе await имеется ключевое различие, поэтому для каждой итерации цикл async for дает управление, поэтому вместо него могут выполняться другие сопрограммы.

Опять же, чтобы повторить итерацию, все это уже было добавлено в Python 3.5 (см. PEP 492), все, что является новым в Python 3.6 что вы можете использовать такой цикл в понимании списка. И в выражениях генераторов, и в понимании набора и диктата, если на то пошло.

И последнее, но не менее важное: тот же набор изменений также позволил использовать await <expression> в разделе выражения понимания, поэтому:

[await func(i) for i in someiterable]

теперь возможно.

Ответ 2

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

Это понимание неверно. Итерации цикла async for не могут выполняться параллельно. async for такой же последовательный, как регулярный цикл for.

Асинхронная часть async for заключается в том, что она позволяет итератору await от имени сопроцессора. Он предназначен только для использования в асинхронных сопрограммах и только для использования на специальных асинхронных итерациях. Помимо этого, он в основном похож на обычный цикл for.