在 Python 众多的 HTTP 客户端中,最有名的莫过于requests
、aiohttp
和httpx
。在不借助其余第三方库的状况下,requests
只能发送同步请求;aiohttp
只能发送异步请求;httpx
既能发送同步请求,又能发送异步请求。python
所谓的同步请求,是指在单进程单线程的代码中,发起一次请求后,在收到返回结果以前,不能发起下一次请求。所谓异步请求,是指在单进程单线程的代码中,发起一次请求后,在等待网站返回结果的时间里,能够继续发送更多请求。json
今天咱们来一个浅度测评,仅仅以屡次发送 POST 请求这个角度来对比这三个库的性能。session
测试使用的 HTTP 服务地址为http://122.51.39.219:8000/query,向它发送 POST 请求的格式以下图所示:app
请求发送的 ts 字段日期距离今天大于10天,那么返回{"success": false}
,若是小于等于10天,那么返回{"success": true}
。dom
首先咱们经过各个客户端使用相同的参数只发送一次请求,看看效果。异步
import requests
resp = requests.post('http://122.51.39.219:8000/query',
json={'ts': '2020-01-20 13:14:15'}).json()
print(resp)
复制代码
运行效果以下图所示:async
import httpx
resp = httpx.post('http://122.51.39.219:8000/query',
json={'ts': '2020-01-20 13:14:15'}).json()
print(resp)
复制代码
httpx 的同步模式与 requests 代码重合度99%,只须要把requests
改为httpx
便可正常运行。以下图所示:post
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())
复制代码
运行效果以下图所示:性能
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 的代码与 httpx 异步模式的代码重合度90%,只不过把AsyncClient
换成了ClientSession
,另外,在使用 httpx 时,当你await client.post
时就已经发送了请求。可是当使用aiohttp
时,只有在awiat resp.json()
时才会真正发送请求。
咱们如今随机生成一个距离今天在5-15天的日期,发送到 HTTP接口中。若是日期距离今天超过10天,那么返回的数据的 False,若是小于等于10天,那么返回的数据是 True。
咱们发送100次请求,计算总共耗时。
在前几天的文章中,咱们提到,使用requests.post
每次都会建立新的链接,速度较慢。而若是首先初始化一个 Session,那么 requests 会保持链接,从而大大提升请求速度。因此在此次测评中,咱们分别对两种状况进行测试。
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次请求,requests 不保持链接时耗时2.7秒
对代码稍做修改,使用同一个 Session 发送请求:
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次请求,requests 保持链接耗时1.4秒
代码以下:
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秒左右。
测试代码以下:
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次请求,使用 aiohttp 耗时0.3秒左右
因为 request 保持链接的速度比不保持链接快,因此咱们这里只用保持链接的方式来测试。而且不打印返回的结果。
运行效果以下图所示:
发送1000次请求,requests 耗时16秒左右
运行效果以下图所示:
发送1000次请求,httpx 同步模式耗时18秒左右
运行效果以下图所示:
发送1000次请求,httpx 异步模式耗时5秒左右
运行效果以下图所示:
发送1000次请求,aiohttp 耗时4秒左右
若是你只发几条请求。那么使用 requests 或者 httpx 的同步模式,代码最简单。
若是你要发送不少请求,可是有些地方要发送同步请求,有些地方要发送异步请求,那么使用 httpx 最省事。
若是你要发送不少请求,而且越快越好,那么使用 aiohttp 最快。
这篇测评文章只是一个很是浅度的评测,只考虑了请求速度这一个角度。若是你要在生产环境使用,那么你能够作更多实验来看是否是符合你的实际使用状况。