python 線程池

來源:互聯網
上載者:User

標籤:

Python的並發處理能力臭名昭著。先撇開線程以及GIL方面的問題不說,我覺得多線程問題的根源不在技術上而在於理念。大部分關於Pyhon線程和多進程的資料雖然都很不錯,但卻過於細節。這些資料講的都是虎頭蛇尾,到了真正實際使用的部分卻草草結束了。

傳統例子

DDG https://duckduckgo.com/搜尋“Python threading
tutorial”關鍵字,結果基本上卻都是相同的類+隊列的樣本。

標準線程多進程,生產者/消費者樣本:

這裡是代碼,如果用其他模式貼出大段代碼會很不美觀。文字模式點這裡 here 

Mmm.. 感覺像是java代碼

在此我不想印證採用生產者/消費者模式來處理線程/多進程是錯誤的—?確實沒問題。實際上這也是解決很多問題的最佳選擇。但是,我卻不認為這是日常工作中常用的方式。

!

問題所在

一開始,你需要一個執行下面操作的鋪墊類。接著,你需要建立一個傳遞對象的隊列,並在隊列兩端即時監聽以完成任務。(很有可能需要兩個隊列互相通訊或者儲存資料)

Worker越多,問題越大.

下一步,你可能會考慮把這些worker放入一個線程池一邊提高Python的處理速度。下面是
IBM tutorial 上關於線程較好的範例程式碼。這是大家常用到的利用多執行緒web頁面的情境

 Seriously, Medium. Fix your code support. Code is Here.


感覺效果應該很好,但是看看這些代碼!初始化方法、線程跟蹤,最糟的是,如果你也和我一樣是個容易犯死結問題的人,這裡的join語句就要出錯了。這樣就開始變得更加複雜了!

到現在為止都做了些什嗎?基本上沒什麼。上面的代碼都是些基礎功能,而且很容易出錯。(天啊,我忘了寫上在隊列對象上調用task_done()方法(我懶得修複這個問題在重新)),這真是性價比太低。所幸的是,我們有更好的辦法.

引入:Map

Map是個很酷的小功能,也是簡化Python並發代碼的關鍵。對那些不太熟悉Map的來說,它有點類似Lisp.它就是序列化的功能映射功能. e.g.

urls = [‘, ‘]results = map(urllib2.urlopen, urls)

 

這裡調用urlopen方法,並把之前的調用結果全都返回並按順序儲存到一個集合中。這有點類似

results = []for url in urls:     results.append(urllib2.urlopen(url))

 

Map能夠處理集合按順序遍曆,最終將調用產生的結果儲存在一個簡單的集合當中。

為什麼要提到它?因為在引入需要的包檔案後,Map能大大簡化並發的複雜度!

 

 

 

支援Map並發的包檔案有兩個:

Multiprocessing,還有少為人知的但卻功能強大的子檔案 multiprocessing.dummy. .


Digression這是啥東西?沒聽說過線程引用叫dummy的多進程包檔案。我也是直到最近才知道。它在多進程的說明文檔中也只被提到了一句。它的效果也只是讓大家直到有這麼個東西而已。這可真是營銷的失誤!

Dummy是一個多進程包的完整拷貝。唯一不同的是,多進程包使用進程,而dummy使用線程(自然也有Python本身的一些限制)。所以一個有的另一個也有。這樣在兩種模式間切換就十分簡單,並且在判斷架構調用時使用的是IO還是CPU模式非常有協助.

!

準備開始

準備使用帶有並發的map功能首先要匯入相關包檔案:

from multiprocessing import Poolfrom multiprocessing.dummy import Pool as ThreadPool

 

然後初始化:

pool = ThreadPool()

 

就這麼簡單一句解決了example2.py中build_worker_pool的功能. 具體來講,它首先建立一些有效worker啟動它並將其儲存在一些變數中以便隨時訪問。

pool對象需要一些參數,但現在最緊要的就是:進程。它可以限定線程池中worker的數量。如果不填,它將採用系統的核心數作為初值.

 

一般情況下,如果你進行的是計算密集型多進程任務,核心越多意味著速度越快(當然這是有前提的)。但如果是涉及到網路計算方面,影響的因素就千差萬別。所以最好還是能給出合適的線程池大小數。

pool = ThreadPool(4) # Sets the pool size to 4

 

如果啟動並執行線程很多,頻繁的切換線程會十分影響工作效率。所以最好還是能通過調試找出任務調度的時間平衡點。

好的,既然已經建好了線程池對象還有那些簡單的並發內容。咱們就來重寫一些example2.py中的url opener吧!

!

看吧!只用4行代碼就搞定了!其中三行還是固定寫法。使用map方法簡單的搞定了之前需要40行代碼做的事!為了增加趣味性,我分別統計了不同線程池大小的已耗用時間。

結果:

效果驚人!看來調試一下確實很有用。當線程池大小超過9以後,在我本機上的運行效果已相差無幾。

的不錯哦!

樣本 2:

產生上千張映像的縮圖:

現在咱們看一年計算密集型的任務!我最常遇到的這類問題之一就是大量影像檔夾的處理。

其中一項任務就是建立縮圖。這也是並發中比較成熟的一項功能了。

基礎單線程建立過程

作為樣本來說稍微有點複雜。但其實就是傳一個檔案夾目錄進來,擷取到裡面所有的圖片,分別建立好縮圖然後儲存到各自的目錄當中。

在我的電腦上,處理大約6000張圖片大約耗時27.9秒.

如果使用並發map處理替代其中的for迴圈:

!

只用了5.6 !

就改了幾行代碼速度卻能得到如此巨大的提升。最終版本的處理速度還要更快。因為我們將計算密集型與IO密集型任務指派到各自獨立的線程和進程當中,這也許會容易造成死結,但相對於map強勁的功能,通過簡單的調試我們最終總能設計出優美、高可靠性的程式。就現在而言,也別無它法。

好了。來感受一下一行代碼的並發程式吧。

python 線程池

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.