網路非同步請求之gevent
- 2020 年 1 月 2 日
- 筆記
我們知道對於網路請求這種IO bound的場景來說,最怕的就是某個請求阻塞了其餘的操作,讓並發性大大降低。今天就來介紹一款python下的並發庫-gevent。
首先看一下他自己的介紹:
gevent是一個基於libev的並發庫。它為各種並發和網路相關的任務提供了整潔的API。
嗯,確實很簡潔,很易使用。待會我們就見識到了。
同步IO
首先我們來看看傳統的IO請求。 比如我們請求:http://httpbin.org/ip 發個http get請求會得到我們的ip地址,如:
{ "origin": "183.240.202.14" }我們來寫個腳本連續發50個get請求到這個地址,以模擬多個請求。(腳本命名為get.py)
import requests url = 'http://httpbin.org/ip' for i in range(50): print("{}: {}".format(i, requests.get(url).text))統計一下運行時間:
$ time python3 get.py (輸出略...) python3 get.py 0.56s user 0.06s system 1% cpu 35.606 total
大概花費35s鍾,當然不同網路環境可能結果不同。而且列印出來的結果是按照1, 2, 3...50這樣的順序來的,說明整個請求是同步的,一個請求結束再發下一個請求。
使用gevent
我們再來寫一個gevent版的get.py,命名為gevent_get.py
import requests import gevent import gevent.monkey # 這裡將socket變成非同步 gevent.monkey.patch_socket() url = 'http://httpbin.org/ip' def hello(i): print("{}: {}".format(i, requests.get(url).text)) tasks = [gevent.spawn(hello, i) for i in range(50)] gevent.joinall(tasks)再來看看運行時間:
$ time python3 gevent_get.py (輸出略...) python3 gevent_get.py 0.49s user 0.06s system 39% cpu 1.403 total
我的天!才1.4秒左右,而且列印出來的結果沒有按照1, 2, 3...50這樣排列,而是按照隨機順序排列的,說明整個請求是非同步非阻塞的。
結論
我又多試了幾次,gevent的效率確實牛,遠遠高於同步io請求。最近在我的一個爬蟲小項目裡面用進程池 + gevent,爬取80個頁面,大概花費40s左右,每個頁面只要0.5s,而且還包括DOM解析的時間,而用同步請求則花費大概300s左右。
gevent的更多用法請參考其官方文檔。這麼簡單又好用的庫趕緊試試吧。^_^
