多線程與多進程的理解
阿新 • • 發佈:2018-07-06
多個 操作系統 常見 RoCE 參數 高效 unix 快的 解釋
參考https://www.liaoxuefeng.com/
線程是最小的執行單元,而進程由至少一個線程組成。如何調度進程和線程,完全由操作系統決定,程序自己不能決定什麽時候執行,執行多長時間。 多進程和多線程的程序涉及到同步、數據共享的問題,編寫起來更復雜。 在Unix/Linux下,可以使用fork()調用實現多進程。 要實現跨平臺的多進程,可以使用multiprocessing模塊。 進程間通信是通過Queue、Pipes等實現的 多線程和多進程最大的不同在於,多進程中,同一個變量,各自有一份拷貝存在於每個進程中,互不影響,而多線程中,所有變量都由所有線程共享,所以,任何一個變量都可以被任何一個線程修改,因此,線程之間共享數據最大的危險在於多個線程同時改一個變量,把內容給改亂了。 因為Python的線程雖然是真正的線程,但解釋器執行代碼時,有一個GIL鎖:Global Interpreter Lock,任何Python線程執行前,必須先獲得GIL鎖,然後,每執行100條字節碼,解釋器就自動釋放GIL鎖,讓別的線程有機會執行。這個GIL全局鎖實際上把所有線程的執行代碼都給上了鎖,所以,多線程在Python中只能交替執行,即使100個線程跑在100核CPU上,也只能用到1個核。 不過,也不用過於擔心,Python雖然不能利用多線程實現多核任務,但可以通過多進程實現多核任務。多個Python進程有各自獨立的GIL鎖,互不影響。 小結 多線程編程,模型復雜,容易發生沖突,必須用鎖加以隔離,同時,又要小心死鎖的發生。 Python解釋器由於設計時有GIL全局鎖,導致了多線程無法利用多核。多線程的並發在Python中就是一個美麗的夢。 在多線程環境下,每個線程都有自己的數據。一個線程使用自己的局部變量比使用全局變量好,因為局部變量只有線程自己能看見,不會影響其他線程,而全局變量的修改必須加鎖。 一個ThreadLocal變量雖然是全局變量,但每個線程都只能讀寫自己線程的獨立副本,互不幹擾。ThreadLocal解決了參數在一個線程中各個函數之間互相傳遞的問題 計算密集型 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 IO密集型任務執行期間,99%的時間都花在IO上,花在CPU上的時間很少,因此,用運行速度極快的C語言替換用Python這樣運行速度極低的腳本語言,完全無法提升運行效率。對於IO密集型任務,最合適的語言就是開發效率最高(代碼量最少)的語言,腳本語言是首選,C語言最差。 對應到Python語言,單線程的異步編程模型稱為協程,有了協程的支持,就可以基於事件驅動編寫高效的多任務程序。我們會在後面討論如何編寫協程。 分布式進程 在Thread和Process中,應當優選Process 因為Process更為穩定,而且Process可以分布到多臺機器上,而Thread最多只能分布到同一臺機器的多個CPU中 小結 Python的分布式進程接口簡單,封裝良好,適合需要把繁重任務分布到多臺機器的環境下。 註意Queue的作用是用來傳遞任務和接收結果,每個任務的描述數據量要盡量小。比如發送一個處理日誌文件的任務,就不要發送幾百兆的日誌文件本身,而是發送日誌文件存放的完整路徑,由Worker進程再去共享的磁盤上讀取文件
多線程與多進程的理解