天天看點

python 程序和線程之程序 vs. 線程

python學習筆記,特做記錄,分享給大家,希望對大家有所幫助。

程序 vs. 線程

我們介紹了多程序和多線程,這是實作多任務最常用的兩種方式。現在,我們來讨論一下這兩種方式的優缺點。

首先,要實作多任務,通常我們會設計Master-Worker模式,Master負責配置設定任務,Worker負責執行任務,是以,多任務環境下,通常是一個Master,多個Worker。

如果用多程序實作Master-Worker,主程序就是Master,其他程序就是Worker。

如果用多線程實作Master-Worker,主線程就是Master,其他線程就是Worker。

多程序模式最大的優點就是穩定性高,因為一個子程序崩潰了,不會影響主程序和其他子程序。(當然主程序挂了所有程序就全挂了,但是Master程序隻負責配置設定任務,挂掉的機率低)著名的Apache最早就是采用多程序模式。

多程序模式的缺點是建立程序的代價大,在Unix/Linux系統下,用fork調用還行,在Windows下建立程序開銷巨大。另外,作業系統能同時運作的程序數也是有限的,在記憶體和CPU的限制下,如果有幾千個程序同時運作,作業系統連排程都會成問題。

多線程模式通常比多程序快一點,但是也快不到哪去,而且,多線程模式緻命的缺點就是任何一個線程挂掉都可能直接造成整個程序崩潰,因為所有線程共享程序的記憶體。在Windows上,如果一個線程執行的代碼出了問題,你經常可以看到這樣的提示:“該程式執行了非法操作,即将關閉”,其實往往是某個線程出了問題,但是作業系統會強制結束整個程序。

在Windows下,多線程的效率比多程序要高,是以微軟的IIS伺服器預設采用多線程模式。由于多線程存在穩定性的問題,IIS的穩定性就不如Apache。為了緩解這個問題,IIS和Apache現在又有多程序+多線程的混合模式,真是把問題越搞越複雜。

線程切換

無論是多程序還是多線程,隻要數量一多,效率肯定上不去,為什麼呢?

我們打個比方,假設你不幸正在準備中考,每天晚上需要做國文、數學、英語、實體、化學這5科的作業,每項作業耗時1小時。

如果你先花1小時做國文作業,做完了,再花1小時做數學作業,這樣,依次全部做完,一共花5小時,這種方式稱為單任務模型,或者批處理任務模型。

假設你打算切換到多任務模型,可以先做1分鐘國文,再切換到數學作業,做1分鐘,再切換到英語,以此類推,隻要切換速度足夠快,這種方式就和單核CPU執行多任務是一樣的了,以幼稚園小朋友的眼光來看,你就正在同時寫5科作業。

但是,切換作業是有代價的,比如從國文切到數學,要先收拾桌子上的國文書本、鋼筆(這叫儲存現場),然後,打開數學課本、找出圓規直尺(這叫準備新環境),才能開始做數學作業。作業系統在切換程序或者線程時也是一樣的,它需要先儲存目前執行的現場環境(CPU寄存器狀态、記憶體頁等),然後,把新任務的執行環境準備好(恢複上次的寄存器狀态,切換記憶體頁等),才能開始執行。這個切換過程雖然很快,但是也需要耗費時間。如果有幾千個任務同時進行,作業系統可能就主要忙着切換任務,根本沒有多少時間去執行任務了,這種情況最常見的就是硬碟狂響,點視窗無反應,系統處于假死狀态。

是以,多任務一旦多到一個限度,就會消耗掉系統所有的資源,結果效率急劇下降,所有任務都做不好。

計算密集型 vs. IO密集型

是否采用多任務的第二個考慮是任務的類型。我們可以把任務分為計算密集型和IO密集型。

計算密集型任務的特點是要進行大量的計算,消耗CPU資源,比如計算圓周率、對視訊進行高清解碼等等,全靠CPU的運算能力。這種計算密集型任務雖然也可以用多任務完成,但是任務越多,花在任務切換的時間就越多,CPU執行任務的效率就越低,是以,要最高效地利用CPU,計算密集型任務同時進行的數量應當等于CPU的核心數。

計算密集型任務由于主要消耗CPU資源,是以,代碼運作效率至關重要。Python這樣的腳本語言運作效率很低,完全不适合計算密集型任務。對于計算密集型任務,最好用C語言編寫。

第二種任務的類型是IO密集型,涉及到網絡、磁盤IO的任務都是IO密集型任務,這類任務的特點是CPU消耗很少,任務的大部分時間都在等待IO操作完成(因為IO的速度遠遠低于CPU和記憶體的速度)。對于IO密集型任務,任務越多,CPU效率越高,但也有一個限度。常見的大部分任務都是IO密集型任務,比如Web應用。

IO密集型任務執行期間,99%的時間都花在IO上,花在CPU上的時間很少,是以,用運作速度極快的C語言替換用Python這樣運作速度極低的腳本語言,完全無法提升運作效率。對于IO密集型任務,最合适的語言就是開發效率最高(代碼量最少)的語言,腳本語言是首選,C語言最差。

異步IO

考慮到CPU和IO之間巨大的速度差異,一個任務在執行的過程中大部分時間都在等待IO操作,單程序單線程模型會導緻别的任務無法并行執行,是以,我們才需要多程序模型或者多線程模型來支援多任務并發執行。

現代作業系統對IO操作已經做了巨大的改進,最大的特點就是支援異步IO。如果充分利用作業系統提供的異步IO支援,就可以用單程序單線程模型來執行多任務,這種全新的模型稱為事件驅動模型,Nginx就是支援異步IO的Web伺服器,它在單核CPU上采用單程序模型就可以高效地支援多任務。在多核CPU上,可以運作多個程序(數量與CPU核心數相同),充分利用多核CPU。由于系統總的程序數量十分有限,是以作業系統排程非常高效。用異步IO程式設計模型來實作多任務是一個主要的趨勢。

對應到Python語言,單線程的異步程式設計模型稱為協程,有了協程的支援,就可以基于事件驅動編寫高效的多任務程式。我們會在後面讨論如何編寫協程。

歡迎關注公衆号 「網羅開發」 ,可領取python測試demo和學習資源,大家一起學python,網羅天下方法,友善你我開發。

希望可以幫助大家,如有問題可加QQ技術交流群: 668562416

如果哪裡有什麼不對或者不足的地方,還望讀者多多提意見或建議

如需轉載請聯系我,經過授權方可轉載,謝謝

歡迎關注公衆号「網羅開發」

python 程式和線程之程式 vs. 線程