Среди многих HTTP-клиентов Python самым известным являетсяrequests
,aiohttp
иhttpx
. Не прибегая к другим сторонним библиотекам,requests
Можно отправлять только синхронные запросы;aiohttp
Можно отправлять только асинхронные запросы;httpx
Могут быть отправлены как синхронные, так и асинхронные запросы.
Так называемый синхронный запрос означает, что в однопроцессном однопоточном коде после инициации запроса следующий запрос не может быть инициирован до тех пор, пока не будет получен возвращаемый результат. Так называемый асинхронный запрос означает, что в однопоточном коде с одним процессом после инициации запроса можно отправить больше запросов, ожидая, пока веб-сайт вернет результат.
Сегодня у нас есть поверхностная оценка, сравнивающая производительность этих трех библиотек только с точки зрения многократной отправки POST-запросов.
Используемый в тесте адрес HTTP-сервиса — http://122.51.39.219:8000/query, а формат отправки на него POST-запроса показан на следующем рисунке:
Если дата поля ts, отправленного запросом, больше 10 дней с сегодняшнего дня, то вернуть{"success": false}
, если меньше или равно 10 дням, то вернуть{"success": true}
.
Во-первых, мы отправляем запрос только один раз с одинаковыми параметрами через каждого клиента, чтобы увидеть эффект.
Отправить запрос
requests
import requests
resp = requests.post('http://122.51.39.219:8000/query',
json={'ts': '2020-01-20 13:14:15'}).json()
print(resp)
Эффект операции показан на следующем рисунке:
httpx
Отправьте синхронный запрос с помощью httpx:
import httpx
resp = httpx.post('http://122.51.39.219:8000/query',
json={'ts': '2020-01-20 13:14:15'}).json()
print(resp)
Синхронный режим httpx на 99% идентичен коду запросов, нужно только поставитьrequests
изменить наhttpx
нормально работать. Как показано ниже:
Отправьте асинхронный запрос с помощью httpx:
import httpx
import asyncio
async def main():
async with httpx.AsyncClient() as client:
resp = await client.post('http://122.51.39.219:8000/query',
json={'ts': '2020-01-20 13:14:15'})
result = resp.json()
print(result)
asyncio.run(main())
Эффект операции показан на следующем рисунке:
aiohttp
import aiohttp
import asyncio
async def main():
async with aiohttp.ClientSession() as client:
resp = await client.post('http://122.51.39.219:8000/query',
json={'ts': '2020-01-20 13:14:15'})
result = await resp.json()
print(result)
asyncio.run(main())
Эффект операции показан на следующем рисунке:
Код aiohttp на 90% идентичен коду асинхронного режима httpx, но кодAsyncClient
заменяетсяClientSession
, а также при использовании httpx, когда выawait client.post
запрос отправлен. но при использованииaiohttp
, только тогда, когдаawiat resp.json()
Только когда запрос действительно отправлен.
отправить 100 запросов
Теперь мы случайным образом генерируем дату, отстоящую от сегодняшнего дня на 5-15 дней, и отправляем ее в HTTP-интерфейс. Если дата отличается от сегодняшнего дня более чем на 10 дней, возвращаемые данные имеют значение False, если она меньше или равна 10 дням, возвращаемые данные имеют значение True.
Мы отправляем 100 запросов, и расчет занимает в общей сложности время.
requests
Несколько дней назад в статье мы упомянули, что использованиеrequests.post
Каждый раз создается новое соединение, которое работает медленнее. И если сеанс инициализируется первым, запросы сохранят соединение, что значительно повышает скорость запросов. Таким образом, в этой оценке мы тестировали два случая отдельно.
не оставаться на связи
import random
import time
import datetime
import requests
def make_request(body):
resp = requests.post('http://122.51.39.219:8000/query', json=body)
result = resp.json()
print(result)
def main():
start = time.time()
for _ in range(100):
now = datetime.datetime.now()
delta = random.randint(5, 15)
ts = (now - datetime.timedelta(days=delta)).strftime('%Y-%m-%d %H:%M:%S')
make_request({'ts': ts})
end = time.time()
print(f'发送100次请求,耗时:{end - start}')
if __name__ == '__main__':
main()
Эффект операции показан на следующем рисунке:
Отправка 100 запросов занимает 2,7 секунды, когда запросы не поддерживают связь
оставайся на связи
Небольшая модификация кода для отправки запроса с использованием той же сессии:
import random
import time
import datetime
import requests
def make_request(session, body):
resp = session.post('http://122.51.39.219:8000/query', json=body)
result = resp.json()
print(result)
def main():
session = requests.Session()
start = time.time()
for _ in range(100):
now = datetime.datetime.now()
delta = random.randint(5, 15)
ts = (now - datetime.timedelta(days=delta)).strftime('%Y-%m-%d %H:%M:%S')
make_request(session, {'ts': ts})
end = time.time()
print(f'发送100次请求,耗时:{end - start}')
if __name__ == '__main__':
main()
Эффект операции показан на следующем рисунке:
При отправке 100 запросов требуется 1,4 секунды, чтобы запросы оставались на связи.
httpx
Режим синхронизации
код показывает, как показано ниже:
import random
import time
import datetime
import httpx
def make_request(client, body):
resp = client.post('http://122.51.39.219:8000/query', json=body)
result = resp.json()
print(result)
def main():
session = httpx.Client()
start = time.time()
for _ in range(100):
now = datetime.datetime.now()
delta = random.randint(5, 15)
ts = (now - datetime.timedelta(days=delta)).strftime('%Y-%m-%d %H:%M:%S')
make_request(session, {'ts': ts})
end = time.time()
print(f'发送100次请求,耗时:{end - start}')
if __name__ == '__main__':
main()
Эффект операции показан на следующем рисунке:
Отправка 100 запросов в синхронном режиме httpx занимает около 1,5 секунд.
Асинхронный режим
код показывает, как показано ниже:
import httpx
import random
import datetime
import asyncio
import time
async def request(client, body):
resp = await client.post('http://122.51.39.219:8000/query', json=body)
result = resp.json()
print(result)
async def main():
async with httpx.AsyncClient() as client:
start = time.time()
task_list = []
for _ in range(100):
now = datetime.datetime.now()
delta = random.randint(5, 15)
ts = (now - datetime.timedelta(days=delta)).strftime('%Y-%m-%d %H:%M:%S')
req = request(client, {'ts': ts})
task = asyncio.create_task(req)
task_list.append(task)
await asyncio.gather(*task_list)
end = time.time()
print(f'发送100次请求,耗时:{end - start}')
asyncio.run(main())
Эффект операции показан на следующем рисунке:
Отправка 100 запросов в асинхронном режиме httpx занимает около 0,6 секунды.
aiohttp
Код теста выглядит следующим образом:
import aiohttp
import random
import datetime
import asyncio
import time
async def request(client, body):
resp = await client.post('http://122.51.39.219:8000/query', json=body)
result = await resp.json()
print(result)
async def main():
async with aiohttp.ClientSession() as client:
start = time.time()
task_list = []
for _ in range(100):
now = datetime.datetime.now()
delta = random.randint(5, 15)
ts = (now - datetime.timedelta(days=delta)).strftime('%Y-%m-%d %H:%M:%S')
req = request(client, {'ts': ts})
task = asyncio.create_task(req)
task_list.append(task)
await asyncio.gather(*task_list)
end = time.time()
print(f'发送100次请求,耗时:{end - start}')
asyncio.run(main())
Эффект операции показан на следующем рисунке:
Отправка 100 запросов занимает около 0,3 секунды с использованием aiohttp
Отправить 1000 запросов
Поскольку скорость запроса, сохраняющего соединение, выше, чем скорость отсутствия соединения, мы используем только метод сохранения соединения для тестирования здесь. и не печатает возвращенный результат.
requests
Эффект операции показан на следующем рисунке:
Отправьте 1000 запросов, запросы занимают около 16 секунд
httpx
Режим синхронизации
Эффект операции показан на следующем рисунке:
Отправьте 1000 запросов, синхронный режим httpx занимает около 18 секунд
Асинхронный режим
Эффект операции показан на следующем рисунке:
Отправьте 1000 запросов, асинхронный режим httpx занимает около 5 секунд
aiohttp
Эффект операции показан на следующем рисунке:
Отправка 1000 запросов, aiohttp занимает около 4 секунд
Суммировать
Если вы отправляете только несколько запросов. Тогда используйте синхронный режим запросов или httpx, код самый простой.
Если вы отправляете много запросов, но некоторые места отправляют синхронные запросы, а некоторые места отправляют асинхронные запросы, использование httpx — самый простой способ.
Если вы отправляете много запросов и чем быстрее, тем лучше, то использование aiohttp будет самым быстрым.
Эта обзорная статья является лишь очень поверхностным обзором, учитывающим только скорость запросов. Если вы хотите использовать его в производственной среде, вы можете провести больше экспериментов, чтобы увидеть, соответствует ли он вашему фактическому варианту использования.