Как не ждать в цикле с асинчио?
Вот пример игрушек, который загружает домашнюю страницу с нескольких сайтов, используя asyncio и aiohttp:
import asyncio
import aiohttp
sites = [
"http://google.com",
"http://reddit.com",
"http://wikipedia.com",
"http://afpy.org",
"http://httpbin.org",
"http://stackoverflow.com",
"http://reddit.com"
]
async def main(sites):
for site in sites:
download(site)
async def download(site):
response = await client.get(site)
content = await response.read()
print(site, len(content))
loop = asyncio.get_event_loop()
client = aiohttp.ClientSession(loop=loop)
content = loop.run_until_complete(main(sites))
client.close()
Если я запустил его, я получаю:
RuntimeWarning: coroutine 'download' was never awaited
Но я не хочу его ждать.
В скрученном я могу сделать:
for site in sites:
download(site)
И если я явно не "уступаю" или не добавляю обратный вызов возвращенному "Отложенному", он просто запускается без блокировки и жалобы. Я не могу получить доступ к результату, но в этом случае мне это не нужно.
В JS я могу сделать:
site.forEarch(site){
donwload(site)
}
И снова он не блокирует и не требует чего-либо с моей стороны.
Я нашел способ сделать:
async def main(sites):
await asyncio.wait([download(site) for site in sites])
Но:
- Это действительно не очевидно, чтобы это выяснить. Мне трудно запомнить.
- трудно понять, что он делает. "Ожидает", кажется, говорит "я блокирую", но не ясно передает блок для завершения всего списка сопрограммы.
- Вы не можете пройти в генератор, он должен быть реальным списком, который я считаю действительно неестественным в Python.
- что, если я буду только ОДНО?
- Что делать, если я не хочу вообще останавливаться на своих задачах и просто планировать их для выполнения, а затем продолжить с остальной частью моего кода?
- это еще более подробное решение, связанное с скруткой и JS.
Это лучший способ?
Ответы
Ответ 1
- Это действительно не очевидно, чтобы это выяснить. Мне трудно запомнить.
Документация на сопрограммы делает довольно понятным, что asyncio.wait
цель.
- трудно понять, что он делает. "Ожидает", кажется, говорит "я блокирую", но не ясно передает блок для завершения всего списка сопрограммы.
Опять же, см. документацию.
- Вы не можете пройти в генератор, он должен быть реальным списком, который я считаю действительно неестественным в Python.
Опять же, см. документацию, в частности asyncio.as_completed
- Что делать, если у меня есть только ОДИН, ожидаемый?
Он должен работать.
- Что делать, если я не хочу вообще останавливаться на своих задачах и просто планировать их для выполнения, а затем продолжить с остальной частью моего кода?
Затем вы можете использовать asyncio.ensure_furture
. Фактически, asyncio.wait
является удобной функцией вокруг asyncio.ensure_future
(и некоторой другой логики).
- это еще более подробное решение, связанное с скруткой и JS.
Может быть, но это не плохо (с моей точки зрения).
Ответ 2
Чтобы запланировать сопрограммы как задачу, используйте asyncio.ensure_future:
for site in sites:
coro = download(site)
future = asyncio.ensure_future(coro)
Он заменяет устаревшую функцию asyncio.async в версии 3.4.4.
Затем вы можете управлять этими фьючерсами с помощью await
, asyncio.wait или asyncio.gather.