Как не ждать в цикле ввода-вывода?
вот пример игрушки, которая загружает домашнюю страницу с нескольких веб-сайтов с помощью 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
но я не хочу ждать его.
в twisted я могу сделать:
for site in sites:
download(site)
и если я явно не" уступаю " или не добавляю обратный вызов к возвращенному отложенному, он просто запускается без блокировки и жалоб. Я не могу получить доступ к результату, но в этом случае он мне не нужен.
в JS я могу do:
site.forEarch(site){
donwload(site)
}
и опять же, он не блокирует и ничего не требует от меня.
я нашел способ это сделать:
async def main(sites):
await asyncio.wait([download(site) for site in sites])
но:
- это действительно не очевидно, чтобы узнать это. Мне трудно вспомнить.
- трудно понять, что он делает. "waits", кажется, говорит "I block", но не передает четко его блок для всего списка coroutine для завершения.
- вы не можете пройти в генератор, он должен быть реальный список, который я очень unatural в Python.
- что, если у меня есть только один ожидаемый ?
- что делать, если я не хочу ждать на всех моих задач, и просто запланировать их для выполнения, а затем продолжить с остальной частью моего кода ?
- это более подробный, чем скрученный и JS-решение.
Это ли лучший способ ?
2 ответов
- это действительно не очевидно, чтобы узнать это. Мне трудно вспомнить.
документация на coroutines делает его довольно ясно, что asyncio.wait
цель есть.
- трудно понять, что он делает. "waits", кажется, говорит "I block", но не передает четко его блок для всего списка coroutine для завершения.
еще раз, см. документация.
- вы не можете передать генератор, это должен быть реальный список, который я чувствую себя очень неестественным в Python.
опять же, см. документацию, в частности asyncio.as_completed
- что, если у меня есть только один ожидаемый ?
он все равно должен работать.
- а если я не хочу ждать на всех моих задач, и просто запланировать их выполнение, а затем продолжить работу с остальной частью моего кода ?
затем вы можете использовать asyncio.ensure_furture
. На самом деле,asyncio.wait
Это удобство
чтобы запланировать корутину в качестве задачи, используйте ввода-вывода.ensure_future:
for site in sites:
coro = download(site)
future = asyncio.ensure_future(coro)
Он заменяет устаревшую функцию ввода-вывода.async в версии 3.4.4.
тогда вы можете управлять этими фьючерсами, используя await
, ввода-вывода.ждать или ввода-вывода.собирайтесь!--4-->.