比requests庫更好用?httpx庫用協(xié)程請求

最近公司 Python 后端項目進(jìn)行重構(gòu)刷袍,整個后端邏輯基本都變更為采用"異步"協(xié)程的方式實現(xiàn)翩隧。看著滿屏幕經(jīng)過 async await(協(xié)程在 Python 中的實現(xiàn))修飾的代碼呻纹,我頓時感到一臉懵逼堆生,不知所措。

雖然之前有了解過"協(xié)程"是什么東西居暖,但并沒有深入探索顽频,于是正好借著這次機會可以好好學(xué)習(xí)一下。

什么是協(xié)程太闺?

簡單來說糯景,協(xié)程是一種基于線程之上,但又比線程更加輕量級的存在省骂。對于系統(tǒng)內(nèi)核來說蟀淮,協(xié)程具有不可見的特性,所以這種由 程序員自己寫程序來管理 的輕量級線程又常被稱作 "用戶空間線程"钞澳。

協(xié)程比多線程好在哪呢怠惶?

  1. 線程的控制權(quán)在操作系統(tǒng)手中,而 協(xié)程的控制權(quán)完全掌握在用戶自己手中轧粟,因此利用協(xié)程可以減少程序運行時的上下文切換策治,有效提高程序運行效率。
  1. 建立線程時兰吟,系統(tǒng)默認(rèn)分配給線程的 棧 大小是 1 M通惫,而協(xié)程更輕量,接近 1 K 混蔼。因此可以在相同的內(nèi)存中開啟更多的協(xié)程履腋。
  1. 由于協(xié)程的本質(zhì)不是多線程而是單線程,所以不需要多線程的鎖機制惭嚣。因為只有一個線程遵湖,也不存在同時寫變量而引起的沖突。在協(xié)程中控制共享資源不需要加鎖晚吞,只需要判斷狀態(tài)即可延旧。所以協(xié)程的執(zhí)行效率比多線程高很多,同時也有效避免了多線程中的競爭關(guān)系槽地。

協(xié)程的適用 & 不適用場景

適用場景:協(xié)程適用于被阻塞的垄潮,且需要大量并發(fā)的場景烹卒。

不適用場景:協(xié)程不適用于存在大量計算的場景(因為協(xié)程的本質(zhì)是單線程來回切換),如果遇到這種情況弯洗,還是應(yīng)該使用其他手段去解決旅急。

初探異步 http 框架 httpx

至此我們對 "協(xié)程" 應(yīng)該有了個大概的了解,但故事說到這里牡整,相信有朋友還是滿臉疑問:"協(xié)程" 對于接口測試有什么幫助呢藐吮?不要著急,答案就在下面逃贝。

相信用過 Python 做接口測試的朋友都對 requests 庫不陌生谣辞。requests 中實現(xiàn)的 http 請求是同步請求,但其實基于 http 請求 IO 阻塞的特性沐扳,非常適合用協(xié)程來實現(xiàn) "異步" http 請求從而提升測試效率泥从。

相信早就有人注意到了這點,于是在 Github 經(jīng)過了一番探索后沪摄,果不其然躯嫉,最終尋找到了支持協(xié)程 "異步" 調(diào)用 http 的開源庫: httpx

什么是 httpx

httpx 是一個幾乎繼承了所有 requests 的特性并且支持 "異步" http 請求的開源庫。簡單來說杨拐,可以認(rèn)為 httpx 是強化版 requests祈餐。

下面大家可以跟著我一起見識一下 httpx 的強大

安裝

httpx 的安裝非常簡單,在 Python 3.6 以上的環(huán)境執(zhí)行

pip install httpx

最佳實踐

俗話說得好哄陶,效率決定成敗帆阳。我分別使用了 httpx 異步 和 同步 的方式對批量 http 請求進(jìn)行了耗時比較,來一起看看結(jié)果吧~

首先來看看同步 http 請求的耗時表現(xiàn):

import asyncio
import httpx
import threading
import time

def sync_main(url, sign):
    response = httpx.get(url).status_code
    print(f'sync_main: {threading.current_thread()}: {sign}2 + 1{response}')

sync_start = time.time()
[sync_main(url='http://www.baidu.com', sign=i) for i in range(200)]
sync_end = time.time()
print(sync_end - sync_start)

代碼比較簡單屋吨,可以看到在 sync_main 中則實現(xiàn)了同步 http 訪問百度 200 次蜒谤。

運行后輸出如下(截取了部分關(guān)鍵輸出...):

sync_main: <_MainThread(MainThread, started 4471512512)>: 192: 200
sync_main: <_MainThread(MainThread, started 4471512512)>: 193: 200
sync_main: <_MainThread(MainThread, started 4471512512)>: 194: 200
sync_main: <_MainThread(MainThread, started 4471512512)>: 195: 200
sync_main: <_MainThread(MainThread, started 4471512512)>: 196: 200
sync_main: <_MainThread(MainThread, started 4471512512)>: 197: 200
sync_main: <_MainThread(MainThread, started 4471512512)>: 198: 200
sync_main: <_MainThread(MainThread, started 4471512512)>: 199: 200
16.56578803062439

可以看到在上面的輸出中, 主線程沒有進(jìn)行切換(因為本來就是單線程啊喂!)請求按照順序執(zhí)行(因為是同步請求)至扰。

程序運行共耗時 16.6 秒

下面我們試試 "異步" http 請求:

import asyncio
import httpx
import threading
import time

client = httpx.AsyncClient()

async def async_main(url, sign):
    response = await client.get(url)
    status_code = response.status_code
    print(f'async_main: {threading.current_thread()}: {sign}:{status_code}')

loop = asyncio.get_event_loop()
tasks = [async_main(url='http://www.baidu.com', sign=i) for i in range(200)]
async_start = time.time()
loop.run_until_complete(asyncio.wait(tasks))
async_end = time.time()
loop.close()
print(async_end - async_start)

上述代碼在 async_main 中用 async await 關(guān)鍵字實現(xiàn)了"異步" http鳍徽,通過 asyncio ( 異步 io 庫請求百度首頁 200 次并打印出了耗時。

運行代碼后可以看到如下輸出(截取了部分關(guān)鍵輸出...)

async_main: <_MainThread(MainThread, started 4471512512)>: 56: 200
async_main: <_MainThread(MainThread, started 4471512512)>: 99: 200
async_main: <_MainThread(MainThread, started 4471512512)>: 67: 200
async_main: <_MainThread(MainThread, started 4471512512)>: 93: 200
async_main: <_MainThread(MainThread, started 4471512512)>: 125: 200
async_main: <_MainThread(MainThread, started 4471512512)>: 193: 200
async_main: <_MainThread(MainThread, started 4471512512)>: 100: 200
4.518340110778809

可以看到順序雖然是亂的(56渊胸,99旬盯,67...) (這是因為程序在協(xié)程間不停切換) 但是主線程并沒有切換 (協(xié)程本質(zhì)還是單線程 )台妆。

程序共耗時 4.5 秒

比起同步請求耗時的 16.6 秒 縮短了接近 73 %翎猛!

俗話說得好,一步快接剩,步步快切厘。 在耗時方面,"異步" http 確實比同步 http 快了很多懊缺。當(dāng)然疫稿,"協(xié)程" 不僅僅能在請求效率方面賦能接口測試培他, 掌握 "協(xié)程"后,相信小伙伴們的技術(shù)水平也能提升一個臺階遗座,從而設(shè)計出更優(yōu)秀的測試框架舀凛。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市途蒋,隨后出現(xiàn)的幾起案子猛遍,更是在濱河造成了極大的恐慌,老刑警劉巖号坡,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件懊烤,死亡現(xiàn)場離奇詭異,居然都是意外死亡宽堆,警方通過查閱死者的電腦和手機腌紧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來畜隶,“玉大人壁肋,你說我怎么就攤上這事〈” “怎么了墩划?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長嗡综。 經(jīng)常有香客問我乙帮,道長,這世上最難降的妖魔是什么极景? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任察净,我火速辦了婚禮,結(jié)果婚禮上盼樟,老公的妹妹穿的比我還像新娘氢卡。我一直安慰自己,他們只是感情好晨缴,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布译秦。 她就那樣靜靜地躺著,像睡著了一般击碗。 火紅的嫁衣襯著肌膚如雪筑悴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天稍途,我揣著相機與錄音阁吝,去河邊找鬼。 笑死械拍,一個胖子當(dāng)著我的面吹牛突勇,可吹牛的內(nèi)容都是我干的装盯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼甲馋,長吁一口氣:“原來是場噩夢啊……” “哼埂奈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起定躏,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤挥转,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后共屈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绑谣,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年拗引,在試婚紗的時候發(fā)現(xiàn)自己被綠了借宵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡矾削,死狀恐怖壤玫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情哼凯,我是刑警寧澤欲间,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站断部,受9級特大地震影響猎贴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蝴光,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一她渴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蔑祟,春花似錦趁耗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至径簿,卻和暖如春罢屈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背牍帚。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工儡遮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留乳蛾,地道東北人暗赶。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓鄙币,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蹂随。 傳聞我的和親對象是個殘疾皇子十嘿,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容