Я попробовал образец, представленный в документации библиотеки запросов для python.
С помощью async.map(rs)
я получаю коды ответа, но хочу получить содержимое каждой запрошенной страницы. Это, например, не работает:
out = async.map(rs)
print out[0].content
requests-threads
сейчас существует.Ответы:
Заметка
Приведенный ниже ответ не применим к запросам v0.13.0 +. После того, как этот вопрос был написан, асинхронная функциональность была перенесена в grequests . Однако вы можете просто заменить
requests
наgrequests
ниже, и он должен работать.Я оставил этот ответ как следует, чтобы отразить исходный вопрос, касающийся использования запросов <v0.13.0.
Чтобы выполнить несколько задач в
async.map
асинхронном режиме, вам необходимо:async.map
список всех запросов / действийПример:
from requests import async # If using requests > v0.13.0, use # from grequests import async urls = [ 'http://python-requests.org', 'http://httpbin.org', 'http://python-guide.org', 'http://kennethreitz.com' ] # A simple task to do to each response object def do_something(response): print response.url # A list to hold our things to do via async async_list = [] for u in urls: # The "hooks = {..." part is where you define what you want to do # # Note the lack of parentheses following do_something, this is # because the response will be used as the first argument automatically action_item = async.get(u, hooks = {'response' : do_something}) # Add the task to our list of things to do via async async_list.append(action_item) # Do our list of things to do via async async.map(async_list)
источник
from grequests import async
не работают .. и это определение что-то работает для меняdef do_something(response, **kwargs):
, я нахожу его из stackoverflow.com/questions/15594015/…from requests import async
наimport grequests as async
сработала у меня.async
в настоящее время является независимым модуль:grequests
.Смотрите здесь: https://github.com/kennethreitz/grequests
И там: Идеальный метод для отправки нескольких HTTP-запросов через Python?
установка:
Применение:
построить стек:
import grequests urls = [ 'http://www.heroku.com', 'http://tablib.org', 'http://httpbin.org', 'http://python-requests.org', 'http://kennethreitz.com' ] rs = (grequests.get(u) for u in urls)
отправить стек
результат выглядит как
[<Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>]
Похоже, что grequests не устанавливает ограничения для одновременных запросов, т.е. когда несколько запросов отправляются на один и тот же сервер.
источник
results = grequests.map(rs)
коду после этой строки заблокироваться, я смогу увидеть асинхронный эффект?Я тестировал как запросы-фьючерсы, так и grequests . Grequests работает быстрее, но приносит исправления обезьяны и дополнительные проблемы с зависимостями. request-futures в несколько раз медленнее, чем grequests. Я решил написать свои собственные и просто обернул запросы в ThreadPoolExecutor, и это было почти так же быстро, как grequests, но без внешних зависимостей.
import requests import concurrent.futures def get_urls(): return ["url1","url2"] def load_url(url, timeout): return requests.get(url, timeout = timeout) with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor: future_to_url = {executor.submit(load_url, url, 10): url for url in get_urls()} for future in concurrent.futures.as_completed(future_to_url): url = future_to_url[future] try: data = future.result() except Exception as exc: resp_err = resp_err + 1 else: resp_ok = resp_ok + 1
источник
возможно, запросы-фьючерсы - другой выбор.
from requests_futures.sessions import FuturesSession session = FuturesSession() # first request is started in background future_one = session.get('http://httpbin.org/get') # second requests is started immediately future_two = session.get('http://httpbin.org/get?foo=bar') # wait for the first request to complete, if it hasn't already response_one = future_one.result() print('response one status: {0}'.format(response_one.status_code)) print(response_one.content) # wait for the second request to complete, if it hasn't already response_two = future_two.result() print('response two status: {0}'.format(response_two.status_code)) print(response_two.content)
Также рекомендуется в офисном документе . Если вы не хотите задействовать gevent, это хороший вариант.
источник
ThreadPoolExecutor(max_workers=10)
У меня много проблем с большинством опубликованных ответов - они либо используют устаревшие библиотеки, которые были перенесены с ограниченными функциями, либо предоставляют решение со слишком большим количеством магии при выполнении запроса, что затрудняет обработку ошибок. Если они не попадают в одну из вышеперечисленных категорий, они являются сторонними библиотеками или являются устаревшими.
Некоторые решения работают нормально только в http-запросах, но решения не подходят для любых других запросов, что просто смешно. Здесь не требуется строго индивидуального решения.
Простого использования встроенной библиотеки python
asyncio
достаточно для выполнения асинхронных запросов любого типа, а также обеспечения достаточной гибкости для обработки сложных и специфичных для конкретных случаев ошибок.import asyncio loop = asyncio.get_event_loop() def do_thing(params): async def get_rpc_info_and_do_chores(id): # do things response = perform_grpc_call(id) do_chores(response) async def get_httpapi_info_and_do_chores(id): # do things response = requests.get(URL) do_chores(response) async_tasks = [] for element in list(params.list_of_things): async_tasks.append(loop.create_task(get_chan_info_and_do_chores(id))) async_tasks.append(loop.create_task(get_httpapi_info_and_do_chores(ch_id))) loop.run_until_complete(asyncio.gather(*async_tasks))
Принцип работы прост. Вы создаете серию задач, которые хотите выполнять асинхронно, а затем запрашиваете цикл для выполнения этих задач и выхода по завершении. Никаких дополнительных библиотек из-за отсутствия поддержки или отсутствия функциональности не требуется.
источник
async
. Тогда можно, например, сделатьawait response = requests.get(URL)
. Нет?requests
чуть быстрее (а в некоторых случаях медленнее), чем просто синхронный вызов списка URL-адресов. Например, запрос конечной точки, которому требуется 3 секунды, чтобы ответить 10 раз, с использованием описанной выше стратегии, занимает около 30 секунд. Если вам нужна настоящаяasync
производительность, вам нужно использовать что-то вродеaiohttp
.run_until_complete
- это если вы не используете модуль потоковой передачи, который делегирует асинхронность на уровень ОС. Прочтите о проблеме GIL в python для получения дополнительной информацииrequests.get
. Но вопрос в том, как выполнять асинхронные запросы сrequests
библиотекой python . Этот ответ этого не делает, поэтому моя критика остается в силе.Я знаю, что на некоторое время это было закрыто, но я подумал, что может быть полезно продвигать другое асинхронное решение, построенное на библиотеке запросов.
list_of_requests = ['http://moop.com', 'http://doop.com', ...] from simple_requests import Requests for response in Requests().swarm(list_of_requests): print response.content
Документы здесь: http://pythonhosted.org/simple-requests/
источник
Если вы хотите использовать asyncio, то
requests-async
предоставляет функции async / await дляrequests
- https://github.com/encode/requests-asyncисточник
Вы можете использовать
httpx
для этого.import httpx async def get_async(url): async with httpx.AsyncClient() as client: return await client.get(url) urls = ["http://google.com", "http://wikipedia.org"] # Note that you need an async context to use `await`. await asyncio.gather(*map(get_async, urls))
если вам нужен функциональный синтаксис, библиотека gamla помещает его в
get_async
.Тогда ты можешь сделать
await gamla.map(gamla.get_async(10), ["http://google.com", "http://wikipedia.org"])
В
10
ожидания в секундах.(отказ от ответственности: я являюсь его автором)
источник
respx
для насмешек / тестирования :)await asyncio.gather(*map(get_async, urls)) ^ SyntaxError: invalid syntax
Пожалуйста, проведитеawait
.from threading import Thread threads=list() for requestURI in requests: t = Thread(target=self.openURL, args=(requestURI,)) t.start() threads.append(t) for thread in threads: thread.join() ... def openURL(self, requestURI): o = urllib2.urlopen(requestURI, timeout = 600) o...
источник
Я уже некоторое время использую запросы python для асинхронных вызовов API github gist.
Для примера см. Код здесь:
https://github.com/davidthewatson/flasgist/blob/master/views.py#L60-72
Этот стиль Python может быть не самым ярким примером, но я могу заверить вас, что код работает. Сообщите мне, если вас это смущает, и я задокументирую это.
источник
К сожалению, насколько мне известно, библиотека запросов не приспособлена для выполнения асинхронных запросов. Вы можете обернуть
async/await
синтаксис вокруг себяrequests
, но это сделает базовые запросы не менее синхронными. Если вам нужны истинные асинхронные запросы, вы должны использовать другие инструменты, которые их предоставляют. Одно из таких решенийaiohttp
(Python 3.5.3+). По моему опыту, он хорошо работает сasync/await
синтаксисом Python 3.7 . Ниже я напишу три реализации выполнения n веб-запросов с использованиемsync_requests_get_all
) с использованием Pythonrequests
библиотекиasync_requests_get_all
) с использованиемrequests
библиотеки Python сasync/await
синтаксисом Python 3.7 иasyncio
async_aiohttp_get_all
) сaiohttp
библиотекой Python, заключенной вasync/await
синтаксис Python 3.7, иasyncio
import time import asyncio import requests import aiohttp from types import SimpleNamespace durations = [] def timed(func): """ records approximate durations of function calls """ def wrapper(*args, **kwargs): start = time.time() print(f'{func.__name__:<30} started') result = func(*args, **kwargs) duration = f'{func.__name__:<30} finsished in {time.time() - start:.2f} seconds' print(duration) durations.append(duration) return result return wrapper async def fetch(url, session): """ asynchronous get request """ async with session.get(url) as response: response_json = await response.json() return SimpleNamespace(**response_json) async def fetch_many(loop, urls): """ many asynchronous get requests, gathered """ async with aiohttp.ClientSession() as session: tasks = [loop.create_task(fetch(url, session)) for url in urls] return await asyncio.gather(*tasks) @timed def asnyc_aiohttp_get_all(urls): """ performs asynchronous get requests """ loop = asyncio.get_event_loop() return loop.run_until_complete(fetch_many(loop, urls)) @timed def sync_requests_get_all(urls): """ performs synchronous get requests """ # use session to reduce network overhead session = requests.Session() return [SimpleNamespace(**session.get(url).json()) for url in urls] @timed def async_requests_get_all(urls): """ asynchronous wrapper around synchronous requests """ loop = asyncio.get_event_loop() # use session to reduce network overhead session = requests.Session() async def async_get(url): return session.get(url) async_tasks = [loop.create_task(async_get(url)) for url in urls] return loop.run_until_complete(asyncio.gather(*async_tasks)) if __name__ == '__main__': # this endpoint takes ~3 seconds to respond, # so a purely synchronous implementation should take # little more than 30 seconds and a purely asynchronous # implementation should take little more than 3 seconds. urls = ['https://postman-echo.com/delay/3']*10 sync_requests_get_all(urls) async_requests_get_all(urls) asnyc_aiohttp_get_all(urls) print('----------------------') [print(duration) for duration in durations]
На моей машине это результат:
sync_requests_get_all started sync_requests_get_all finsished in 30.92 seconds async_requests_get_all started async_requests_get_all finsished in 30.87 seconds asnyc_aiohttp_get_all started asnyc_aiohttp_get_all finsished in 3.22 seconds ---------------------- sync_requests_get_all finsished in 30.92 seconds async_requests_get_all finsished in 30.87 seconds asnyc_aiohttp_get_all finsished in 3.22 seconds
источник
Я также пробовал некоторые вещи, используя асинхронные методы в python, но мне гораздо больше повезло с использованием twisted для асинхронного программирования. Он имеет меньше проблем и хорошо задокументирован. Вот ссылка на что-то похожее на то, что вы пытаетесь скрутить.
http://pythonquirks.blogspot.com/2011/04/twisted-asynchronous-http-request.html
источник