Python高手進階|實戰4大併發祕籍 黑羽_123

今天我們就從Python的併發開刀,大家都知道併發有幾招,那這幾招的性能如何呢,我們一起來實戰PK一下!

小編整理了一些Python學習內容,我把它推薦給你!Python資料+Qun  69286 - 7294 就能獲得全部資料!免費學習視頻+項目源碼,並且在學習的過程中,還可以參與我們的訓練營學習!

要點:

  • 手動線程池

  • concurrent.futures線程池

  • concurrent.futures進程池

  • gevent協程

1.實戰爬取維基百科例子

平時我們有很多任務,尤其是比較耗時的大量任務要處理,一定會用到併發處理。畢竟串行太慢了,下面我們去爬一個維基百科的網站:

我們來爬取紅框裏面的導航文本部分,這是一個非常簡單的爬蟲(關於爬蟲的文章前面寫的太多太多了,大家可以翻歷史文章)

1).連接網頁

2).爬取網頁

-函數設計的時候我們希望入參是一個元組(url,words),方便後面做併發處理
-網頁非常簡單,直接用requests取爬取,獲取text
-用pyquery來解析網頁,獲取對國家的描述
-數據結構用字典對來存儲

小編整理了一些Python學習內容,我把它推薦給你!Python資料+Qun  69286 - 7294 就能獲得全部資料!免費學習視頻+項目源碼,並且在學習的過程中,還可以參與我們的訓練營學習!

2.PK前做點準備工作

1).如果我們現在要爬取100個國家的信息,有幾種辦法呢:
最慢的串行爬取
自己手動構建一個線程池,把要爬取的100國家都扔到共享隊列裏面,讓多個線程共享爬取
利用concurrent.futures標準庫裏的線程池來爬去
用多進程來爬取,雖然網頁請求是CPU密集型的,用進程有點浪費,但是我們作爲對比,是可以試一下的
用協程也叫微線程,是一種綠色線程,用來做高併發很爽

2).爲了準確的計算每一種方法的耗時,我們寫一個函數專門來計算時間:

下面我們用上面的5種方法逐一運行,爲了簡單期間我們統一爬取5個國家,每種方法上面用裝飾器@cost_time來計算一下,看看到底哪種方便比較簡單,速度又最快~~

3.慢慢的串行處理

先來段最通俗的one by one的串行處理

4.手動建多線程共享隊列

利用queue有鎖的功能,手動把數據塞進隊列,然後多個線程共享爬取

5.用標準庫裏面的線程池

與其動手造輪子,不如用無所不能的庫,Python裏面的庫真的太多太多了!這也是Python爲啥這麼火爆的原因之一.

發現用系統的線程池跟手動的幾乎差不多,但是大家發現沒有用輪子來處理,代碼量非常小,而且很優美!(這是Python之美,能用輪子儘量用輪子,簡潔高效).
有同學會問,有沒有什麼情況是一定要手動構建線程池,而不能用ThreadPoolExecutor,確實有這樣的情況,大家思考一下,不明白的留言給我,偷偷告訴你.

小編整理了一些Python學習內容,我把它推薦給你!Python資料+Qun  69286 - 7294 就能獲得全部資料!免費學習視頻+項目源碼,並且在學習的過程中,還可以參與我們的訓練營學習!

6.用標準庫的裏進程池

既然上面有線程池,一定有進程池吧。是的,我們下面來看看殺雞用牛刀的多進程處理,需要幾秒呢:

差不多也是5-6秒左右,多進程還是比較快的!但是我們這裏是5個國家,如果500個你不可能開100個進程來處理呢,如果碰到非常巨大的併發量,又要節省系統資源,又要速度很快,怎麼辦呢,我們看最後一招

7.絕招,用協程來併發

用一下gevent這個庫,功能強大使用簡單,對協程的封裝比較好。每當一個協程阻塞時,程序將自動調度,gevent幫我們處理了所有的底層細節

哇協程果然很牛逼,只需要2.8秒左右,非常舒爽的感覺!但是這裏因爲requests庫有個缺點,訪問的時候是上一個訪問結束,才能進行下一次訪問!所以需要用gevent的猴子補丁.另外gevent雖然很好,但是它是大規模併發,如果發起10000個網絡請求,估計很快會被封IP!

好我們來總結一下:
同步處理:17秒
異步手動建線程池:5.5秒
異步標準庫線程池:5.2秒
異步標準庫進程池:5.9秒
併發協程:2.8秒

很明顯用Gevent最快,尤其是在大規模的幾十萬級別的併發處理效果非常明顯.

線程池也是一個不錯的選擇,而且比較靈活,如果需要多個併發任務之間有交互的話,還是需要用線程池.

那進程池呢,我們上面考慮的都是IO 密集型task,如果我們碰到了CPO型的那就必須要多核多CPU運行才能加速。畢竟Python有一個煩人的GIL,好今天的文章就寫到這裏,歡迎留言討論