注:本文是廖大的教程文章,本人也在學習,因為老是記不住,自己手打一邊,代碼也是親自測試。 廖大傳送門
多程序和多線程是實作多任務的常用兩種方式。現在比較一下這兩種方式。
首先要實作一個多任務,通常我們會設計一個 Master-Worker 模式,Master 負責配置設定任務,Worker 負責執行任務。是以,在多任務中,通常是有一個 Master,多個 Worker。
多程序
如果用多程序實作 Master-Worker ,主程序就是 Master ,其他程序就是 Worker。
多程序最大的優點就是穩定性高,因為一個子程序崩潰了,不會影響主程序和其他子程序。(當然主程序挂了,所有的子程序就也挂了,但是通常 Master 隻負責配置設定任務,挂掉的幾率很低。)著名的 Apache 最早就是采用多程序模式。
多程序最大的缺點是建立程序的代價大,在 Unix/Linux 系統下,用 fork 調用還行,在 Windows 下建立程序開銷巨大。另外,作業系統能同時運作的程序也是有限的,在記憶體和 CPU 的限制下,如果有幾千個程序同時運作,作業系統連排程都成問題。
如果用多線程實作 Master-Worker ,主線程就是 Master ,其他線程就是 Worker。
多線程模式通常比多程序要快一些,但也快不到哪去,而且,多線程的緻命缺點是任何一個線程挂掉都可能直接造成整個程序崩潰,因為所有的線程共享程序的記憶體,。在 Windows 上,如果一個線程出現問題,你經常看到這樣的提示,「該程式執行了非法操作,即将關閉」,其實是某個線程出現問題,但是作業系統會關閉整個程序。
在 Windows 下,多線程比多程序效率高,是以微軟的 IIS 伺服器預設采用多線程的模式,由于多線程存在穩定性的問題,是以 IIS 的穩定性就不如 Apache 為了緩解這個問題,IIS 和 Apache 現在又有多線程加多程序的模式,這個不懂,據說問題越高越複雜。
線程切換
無論多線程還是多程序,數量一多,效率肯定上不去,為什麼?
舉個例子
假如你不幸假設你不幸正在準備中考,每天晚上需要做國文、數學、英語、實體、化學這5科的作業,每項作業耗時1小時。
如果你先花1小時做國文作業,做完了,再花1小時做數學作業,這樣,依次全部做完,一共花5小時,這種方式稱為單任務模型,或者批處理任務模型。
假設你打算切換到多任務模型,可以先做1分鐘國文,再切換到數學作業,做1分鐘,再切換到英語,以此類推,隻要切換速度足夠快,這種方式就和單核CPU執行多任務是一樣的了,以幼稚園小朋友的眼光來看,你就正在同時寫5科作業。
但是,切換作業是有代價的,比如從國文切到數學,要先收拾桌子上的國文書本、鋼筆(這叫儲存現場),然後,打開數學課本、找出圓規直尺(這叫準備新環境),才能開始做數學作業。作業系統在切換程序或者線程時也是一樣的,它需要先儲存目前執行的現場環境(CPU寄存器狀态、記憶體頁等),然後,把新任務的執行環境準備好(恢複上次的寄存器狀态,切換記憶體頁等),才能開始執行。這個切換過程雖然很快,但是也需要耗費時間。如果有幾千個任務同時進行,作業系統可能就主要忙着切換任務,根本沒有多少時間去執行任務了,這種情況最常見的就是硬碟狂響,點視窗無反應,系統處于假死狀态。
是以,多任務一旦多到一個限度,就會消耗掉系統所有的資源,結果效率急劇下降,所有任務都做不好。
計算密集型 vs IO密集型
是否采用多任務的的第二個考慮因素是任務的類型,我們可以把任務分為計算密集型和IO密集型
1、計算密集型的特點是要進行大量的計算,消耗 CPU 的資源,比如計算圓周率,視訊的解碼等,全靠 CPU 的運算能力。這種計算密集型任務雖然也可以用多任務完成,但是任務越多,花在任務切換的時間就越多,CPU 執行效率就會降低,是以要想高效利用 CPU 計算密集型任務同時進行的數量應當等于 CPU 的核心數。
計算密集型任務主要消耗 CPU 資源,是以,代碼運作速度至關重要,python這種腳本語言執行效率很低自然沒辦法勝任。對于計算密集型任務,最好才用 C 編寫。
2、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語言,單線程的異步程式設計模型稱為協程,有了協程的支援,就可以基于事件驅動編寫高效的多任務程式。
注意了啊,敲黑闆啦 !!!
前面學習的多程序和多線程大部分情況下都是扯淡的,請以後認真學習異步IO(協程)