Как я могу использовать запросы ввода-вывода?
Я хочу выполнять параллельные задачи http-запроса в asyncio
, но я считаю, что python-requests
будет блокировать цикл обработки событий от asyncio
. Я нашел aiohttp но он не мог предоставить услугу http-запроса с помощью HTTP-прокси.
поэтому я хочу знать, есть ли способ сделать асинхронные http-запросы с помощью asyncio
.
5 ответов:
чтобы использовать запросы (или любые другие библиотеки блокировки) с 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 дополнительные.
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())
просит в настоящее время не поддерживает
asyncio
и нет никаких планов по оказанию такой поддержки. Вполне вероятно, что вы могли бы реализовать пользовательский "транспортный адаптер" (см. здесь) который умеет пользоватьсяasyncio
.Если я окажусь с некоторым временем это то, что я мог бы на самом деле посмотреть, но я ничего не могу обещать.
есть хороший случай асинхронных / ожидающих циклов и потоков в статье Пимина Константина Кефалоукоса легкие параллельные HTTP-запросы с Python и asyncio:
для минимизации общего времени завершения, мы могли бы увеличить размер пула потоков, чтобы соответствовать количеству запросов, которые мы должны сделать. К счастью, это легко сделать, как мы увидим далее. Приведенный ниже список кода является примером того, как сделать двадцать асинхронных 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())
ответы выше по-прежнему используют старые сопрограммы стиля Python 3.4. Вот что вы напишете, если у вас есть Python 3.5+.
aiohttp
поддерживает HTTP-прокси теперьimport aiohttp import asyncio async def fetch(session, url): async with session.get(url) as response: return await response.text() async def main(): urls = [ 'http://python.org', 'https://google.com', 'http://yifei.me' ] tasks = [] async with aiohttp.ClientSession() as session: for url in urls: tasks.append(fetch(session, url)) htmls = await asyncio.gather(*tasks) for html in htmls: print(html[:100]) if __name__ == '__main__': loop = asyncio.get_event_loop() loop.run_until_complete(main())