您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關Python中多線程與多進程有什么區別,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
線程與多線程
什么是線程
一個線程可以看成是一個有序的指令流(完成特定任務的指令),并且可以通過操作系統來調度這些指令流。
線程通常位于進程程里面,由一個程序計數器、一個堆棧和一組寄存器以及一個標識符組成。這些線程是處理器可以分配時間的最小執行單元。
線程之間是可以共享內存并且互相通信的。但是當兩個線程之間開始共享內存,就無法保證線程執行的順序,這可能導致程序錯誤,或者產生錯誤的結果。這個問題我們日后會專門提及。
下面這個圖片展示了多個線程在多個CPU中的存在方式:
線程的類型
在一個典型的操作系統里面,一般會有兩種類型的線程:
1.用戶級線程:我們能夠創建、運行和殺死的線程;
2.內核級線程:操作系統運行的低級別線程;
Python工作在用戶級線程上,我們介紹的內容也主要是在用戶級的線程上運行的。
什么是多線程
現在的CPU基本上都是多線程的CPU,比如我們隨意從京東上找一個Inter的酷睿i5處理器,看看它的產品規格:
這些CPU能夠同時運行多個線程來處理任務,其實從本質上來說,這些CPU是利用一個能夠在多個線程之間快速切換的單個內核來完成多線程的運行的,切換線程的速度足夠快,所以我們并不會感覺到。但實質上,它們并不是同時運行的。
為了形象的理解多線程,我們來回憶一個場景。
在大學時代,期末的時候,有些科目的老師為了不為難大家,把考試設為開卷考試,不知道大家面對開卷考試的時候,做題的順序是怎樣的?
在單線程的工作模式下,我們從選擇題到填空題到簡答題再到分析題,一個一個按順序的寫。
遇到一個特別難的題目,我們就要翻書翻資料了,當然既然是開卷考試,有些題目的答案就不可能直接出現在教科書中,那么我們就要花費更多的時間來找答案,直到考試結束,因為某個難題耗費的翻書時間太多,導致后面一些簡單的題目也沒用做,嗯,開卷都寫不完試卷,掛科名額就給你了。
而在多線程的工作模式下,我們也是按順序寫,但是遇到難題時,我們會稍微從書中找找答案,如果沒找到,就先做下面的題目,把會做的題目做好,做好了容易的題目,再回到那個難題上,仔細從書中的蛛絲馬跡中找答案。
在這個例子里面,我們只是一個人來完成,如果想要更快地完成考試,就得跟其他同學通力合作和分工了。
讓我們看看線程的一些優點:
1.多線程能夠有效提升I/O阻塞型程序的效率;
2.與進程相比,占用的系統資源少;
3.線程間能夠共享資源,方便進行通信;
線程還有一些缺點:
1.Python中有全局解釋器鎖(GIL)的限制;
2.雖然線程之間能夠進行通信,但是容易導致程序結果出錯,使用的時候必須小心;
3.在多線程之間切換的計算代價高,會導致程序的整體性能下降。
進程與多進程
進程在本質上與線程非常相似,進程幾乎可以完成線程能夠完成的任何事情。
按照上面開卷考試的例子,如果我們和室友組成一個小團伙,那么我們就有四個CPU(4個人),四個人分別寫和找不同的答案,這樣考試的效率會提高很多。
一個進程里面,包含一個主線程,還可以生成很多子線程,每個線程都包含自己的寄存器組合堆棧。如果有需要的話,可以將它們組成多線程。
下面是單線程單進程和多線程單進程的示例:
進程的特性
一個進程通常包含以下的內容:
1.進程ID,進程組ID,用戶ID,組ID
2.環境
3.工作目錄
4.程序指令
5.寄存器
6.堆棧
7.文件描述
8.進程間通信工具
9.等等……
進程有以下優點:
1.更好地利用多核處理器;
2.在處理CPU密集型任務時比多線程要好;
3.可以通過多進程來避免全局解釋器鎖(GIL)的局限;
4.崩潰的進程不會導致整個程序的崩潰;
同時,還有以下缺點:
1.進程之間沒有共享資源;
2.進程需要消耗更多的內存;
多進程
在Python中我們可以使用多線程或者多進程的方式來運行我們的代碼以改進傳統的單線程方式的性能。
在單核的CPU上可以使用多線程提高處理能力,但是在現在的計算機CPU中,多核處理器早已普及,為了有效的利用機器的資源,我們有必要使用多進程來發揮機器的價值。
一個CPU內核將任務分配給其他CPU:
通過Python的進程處理模塊multiprocessing,我們可以有效的利用機器上所有的處理器,這有助于我們在處理CPU密集型任務時獲得更高的性能。
使用multiprocessing模塊,查看我們機器上的CPU核心數量:
結果返回一個數字,為CPU核心數。
多進程不僅能夠提高我們的計算機的利用率,還能夠避免全局解釋器鎖的限制,一個潛在的缺點是多進程間不能進行共享和通信(可以通過其他手段實現),但是這個缺點同時也使多進程更加容易使用和避免出現崩潰。
Python的局限性
在文章的前面,我們談到了在Python中存在的全局解釋器鎖GIL的局限性。那GIL到底是個什么東西?
GIL本質上是一個互斥鎖,它可以防止多個線程同時執行Python代碼。 它是一個只能由一個線程保持的鎖,如果你想要一個線程去執行代碼,那么在它執行代碼之前,首先必須獲得這個鎖。 這樣做的一個好處是,當它被鎖定的時候,沒有別的進程可以同時運行代碼,一定程度上避免了線程間的沖突:
上面這個圖說明了多個線程如何被GIL阻塞。每個線程必須等待獲取到GIL才能進行下一步的運行,然后再釋放GIL。線程之間使用隨機循環的方式,所以并不能控制和保證哪個線程會先得到GIL。
這樣的設計似乎很反人類,而這也是很多人詬病Python的地方。但是,這個設計確實是保證的多線程之間的內存安全。
現在我們已經了解了線程和進程,以及Python的一些限制,現在是時候了解一下我們如何在應用程序中使用多線程多進程,以提高程序的速度。
并發文件下載
毫無疑問的,展現多線程優點的一個例子就是使用多線程來下載多個圖片或者文件,由于I/O的阻塞性質,下載任務可能是多線程最佳的運用場景了。
http://tool.bitefu.net/jiari/data/2017.txt是一個提供2017年所有節假日的文本文件:
我們訪問10次,獲得10次文本文件,然后保存在本地。
先看看一個普通的爬取:
我們引入了模塊urllib.request,然后創建了一個函數downloadImage()用于下載文件,創建了一個函數main()用于對下載函數進行遍歷20次。
耗時4秒多。
下面看看使用多線程的:
程序的前部分大同小異,后面我們創建了一個threads列表,,然后遍歷10次,創建一個新的線程對象,將其添加到threads列表中,然后啟動該線程。
最后,我們通過遍歷我們的threads列表來調用我們的線程,然后調用join()方法在每個線程上,這確保我們在下載完文件之前,不會執行剩下的代碼。
運行代碼,可以發現程序幾乎同時啟動了10個下載任務,然后在圖片下載完成后,再打印出來。
耗時0.1秒,效率提高很多。
但是需要注意的是,在網絡中進行文件IO,還需要考慮網絡狀況和自身機器的影響,不同的網絡狀況下,完成的效率也不一樣。
并發數字運算
I/O密集型的任務適合于多線程,而CPU密集型的任務則適合用多進程。
在下面的例子里,我們將找出100萬個20000到100000000之間隨機數的質數。
順序運算:
耗時18秒。
多進程運算:
上述就是小編為大家分享的Python中多線程與多進程有什么區別了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。