淺度測評:requests、aiohttp、httpx 我應該用哪一個?


作者 l kingname 來源 l 未聞 Code(ID:itskingname)

以下文章來源於未聞Code ,作者kingname

在武漢,房子里待着,不出去影響世界了,轉載點文章。

在 Python 眾多的 HTTP 客戶端中,最有名的莫過於requestsaiohttphttpx。在不借助其他第三方庫的情況下,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 的同步模式與 requests 代碼重合度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 的代碼與 httpx 異步模式的代碼重合度90%,只不過把AsyncClient換成了ClientSession,另外,在使用 httpx 時,當你await client.post時就已經發送了請求。但是當使用aiohttp時,只有在awiat resp.json() 時才會真正發送請求。

發送100次請求

我們現在隨機生成一個距離今天在5-15天的日期,發送到 HTTP接口中。如果日期距離今天超過10天,那么返回的數據的 False,如果小於等於10天,那么返回的數據是 True。

我們發送100次請求,計算總共耗時。

requests

在前幾天的文章中,我們提到,使用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秒

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次請求,使用 aiohttp 耗時0.3秒左右

發送1000次請求

由於 request 保持連接的速度比不保持連接快,所以我們這里只用保持連接的方式來測試。並且不打印返回的結果。

requests

運行效果如下圖所示:

發送1000次請求,requests 耗時16秒左右

httpx

同步模式

運行效果如下圖所示:

發送1000次請求,httpx 同步模式耗時18秒左右

異步模式

運行效果如下圖所示:

發送1000次請求,httpx 異步模式耗時5秒左右

aiohttp

運行效果如下圖所示:

發送1000次請求,aiohttp 耗時4秒左右

總結

如果你只發幾條請求。那么使用 requests 或者 httpx 的同步模式,代碼最簡單。

如果你要發送很多請求,但是有些地方要發送同步請求,有些地方要發送異步請求,那么使用 httpx 最省事。

如果你要發送很多請求,並且越快越好,那么使用 aiohttp 最快。

這篇測評文章只是一個非常淺度的評測,只考慮了請求速度這一個角度。如果你要在生產環境使用,那么你可以做更多實驗來看是不是符合你的實際使用情況。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM