Как я могу использовать запросы в asyncio?

Я хочу выполнять параллельные задачи запроса http в asyncio, но обнаруживаю, что python-requests блокирует цикл событий asyncio. Я нашел aiohttp, но не смог предоставить службу http-запроса с помощью http-прокси.

Итак, я хочу знать, есть ли способ сделать асинхронные http-запросы с помощью asyncio.

Ответ 1

Чтобы использовать запросы (или любые другие блокирующие библиотеки) с помощью asyncio, вы можете использовать BaseEventLoop.run_in_executor для запуска функции в другом потоке и получения от него получить результат. Например:

import asyncio
import requests

@asyncio.coroutine
def main():
    loop = asyncio.get_event_loop()
    future1 = loop.run_in_executor(None, requests.get, 'http://www.google.com')
    future2 = loop.run_in_executor(None, requests.get, 'http://www.google.co.uk')
    response1 = yield from future1
    response2 = yield from future2
    print(response1.text)
    print(response2.text)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

Это даст оба ответа параллельно.

С помощью python 3.5 вы можете использовать новый синтаксис await/async:

import asyncio
import requests

async def main():
    loop = asyncio.get_event_loop()
    future1 = loop.run_in_executor(None, requests.get, 'http://www.google.com')
    future2 = loop.run_in_executor(None, requests.get, 'http://www.google.co.uk')
    response1 = await future1
    response2 = await future2
    print(response1.text)
    print(response2.text)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

Подробнее см. PEP0492.

Ответ 2

aiohttp можно использовать с прокси-сервером HTTP уже:

import asyncio
import aiohttp


@asyncio.coroutine
def do_request():
    proxy_url = 'http://localhost:8118'  # your proxy address
    response = yield from aiohttp.request(
        'GET', 'http://google.com',
        proxy=proxy_url,
    )
    return response

loop = asyncio.get_event_loop()
loop.run_until_complete(do_request())

Ответ 3

В настоящее время запросы не поддерживают asyncio, и нет такой поддержки. Вероятно, вы могли бы реализовать пользовательский "Транспортный адаптер" (как обсуждалось здесь), который знает, как использовать asyncio.

Если я нахожусь с некоторым временем, это то, над чем я мог бы заглянуть, но я ничего не могу обещать.

Ответ 4

В статье Пимина Константина Кефалукоса есть хороший пример циклов асинхронного/ждущего и потокового Простые параллельные HTTP-запросы с Python и асинхронным:

Чтобы минимизировать общее время завершения, мы могли бы увеличить размер пула потоков, чтобы соответствовать количеству запросов, которые мы должны выполнить. К счастью, это легко сделать, как мы увидим дальше. Ниже приведен код, приведенный ниже, как сделать двадцать асинхронных HTTP-запросов с пулом потоков из двадцати рабочих потоков:

# Example 3: asynchronous requests with larger thread pool
import asyncio
import concurrent.futures
import requests

async def main():

    with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:

        loop = asyncio.get_event_loop()
        futures = [
            loop.run_in_executor(
                executor, 
                requests.get, 
                'http://example.org/'
            )
            for i in range(20)
        ]
        for response in await asyncio.gather(*futures):
            pass


loop = asyncio.get_event_loop()
loop.run_until_complete(main())