Для чего нужен async for?
Я не понимаю, для чего нужен async for. Пожалуйста, подробно объясните что это такое и как им пользоваться. Приведите простой пример и желательно ещё пример реального использования.
Ответы (1 шт):
Очень коротко:
- Обычный for нужен для итерирования по обычным (синхронным) итераторам и итерируемым объектам
- асинхронный for нужен для итерирования по асинхронным итераторам и итерируемым объектам
Это в общем-то и вся разница. По крайней мере, поверхностная разница, к которой прилагается нижняя часть "айсберга" асинхронного программироваия.
Если какая-то библиотека асинхронная (или поддерживает асинхронность), она может возвращать где-то асинхронный итератор/итерируемый объект с набором результатов. Как про это узнать - посмотреть документацию. Вот пример с async for из документации Django 4.1:
async for author in Author.objects.filter(name__startswith="A"):
book = await author.books.afirst()
В своем коде можно реализовать свои асинхронные итераторы или итерирумые объекты.
В обычных итераторах нужно реализовать методы
__iter__(у итераторов__iter__возвращает сам объект, т.е.self) и__next__,__next__выбрасывает исключениеStopIterationпри исчерпании итератора. В итерируемых объектах - просто__iter__, который должен возвращать итератор.В асинхронных итераторах и итерируемых объектах аналогично, но методы должны быть
def __aiter__иasync def __anext__, и__anext__должен бросатьStopAsyncIterationпри исчерпании.
Синхронный пример:
import time
import random
class Iterator:
def __init__(self, n):
self.i = n
def __iter__(self):
return self
def __next__(self):
if self.i <= 0:
raise StopIteration
self.i -= 1
time.sleep(0.5)
return random.randint(0, 100)
def main():
for x in Iterator(10):
print(x)
main()
Асинхронный пример:
import asyncio
import random
class AsyncIterator:
def __init__(self, n):
self.i = n
def __aiter__(self):
return self
async def __anext__(self):
if self.i <= 0:
raise StopAsyncIteration
self.i -= 1
await asyncio.sleep(0.5)
return random.randint(0, 100)
async def main():
async for x in AsyncIterator(10):
print(x)
asyncio.run(main())
Также есть асинхроные генераторы (функции, возвращающие значения через yield), в общем-то единственное синтаксическое отличие от обычных - наличие async перед def:
import asyncio
import random
async def async_generator(n):
for _ in range(n):
yield random.randint(0, 100)
await asyncio.sleep(0.5)
async def main():
async for x in async_generator(10):
print(x)
asyncio.run(main())
Ну и выражения-генераторы с async for нужны чтобы собрать результат в список или другой контейнер:
async def main():
result = [x async for x in async_generator(10)]
print(result)