Как не ждать в цикле ввода-вывода?

вот пример игрушки, которая загружает домашнюю страницу с нескольких веб-сайтов с помощью 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-->.