前言
單線程就是一個工人在搬磚,多線程就是多個工人在搬磚;在相同數量的磚要搬的情況下,多個工人搬磚肯定比一個人搬的快。
那多個工人做事一定比一個工人做事快嗎?那不一定,不過大多數情況下是的。多線程只是可以同時接收多個任務,但不一定馬上去執行任務。這里要看有多少資源(單核 or 多核)和做什么任務(計算密集型任務 or IO密集型任務)。基于這兩個條件進行笛卡爾積形成的場景來分析單線程和多線程的工作效率。
單核:單核處理器指的是只有一個物理核心的處理器。物理核心是處理器中的實際計算單元,能夠執行指令和處理數據。在單核處理器中,只能同時執行一個線程或進程。即使使用多線程編程,也只能通過時間片輪轉的方式在不同線程之間進行切換,每個線程在某個時間片內獨占處理器的執行時間。
多核:多核處理器指的是具有多個物理核心的處理器。多核處理器將多個物理核心集成到一個芯片上,每個核心都是一個獨立的計算單元,能夠并行執行指令和處理數據。每個核心可以獨立地執行一個線程或進程,因此多核處理器可以同時執行多個線程或進程,提供更高的并行處理能力。
計算密集型任務:計算密集型任務是指那些主要依賴 CPU 運算能力的任務。通常涉及大量的數值計算、復雜的算法或模型運算,而對于 I/O 操作的需求相對較低,受限于 CPU 的運算速度。
IO密集型任務:I/O 密集型任務是指那些主要依賴于輸入/輸出操作的任務。這些任務通常需要頻繁地進行文件讀寫、網絡通信、數據庫訪問等 I/O 操作,而對于 CPU 的計算能力需求相對較低。
單核 + 計算密集型任務:
在單核情況下,只有一個物理核心處理器,多線程和單線程最終都落在一個核心處理器(CPU)去處理任務,此時的多線程只是分時段的獲取同一個CPU處理任務。就好比工人使用一個計算器來記賬,最終都依靠計算器計算加減乘除來獲得結果。
在處理計算密集型任務的時候,主要依賴CPU不停的運算來處理任務,這個時候無論是多線程還是單線程,接收單個或多個計算密集型任務,處理效率都沒太大差距,因為只有一個CPU在不停地進行運算處理任務,接收的多個任務也只能一個個依次處理。就好比多個工人都在做記賬任務,而計算器只有一個,需要等一個工人使用計算完后才能交給下一個工人記賬,這個時候一個工人記多筆賬還是多個工人分別記,都沒太大差別,甚至還差一點,工人之間需要交換計算器會產生耗時,這就是多線程之間的切換開銷。
單核+計算密集型任務場景時,使用單線程處理就可以了。
單核 + IO密集型任務:
在處理IO密集型任務的時候,雖然多線程和單線程最終都落在一個核心處理器(CPU)去處理任務,但在處理一個任務的整個過程中,CPU并不需要一直參與運算,此時多線程就可以充分利用CPU。對于單線程,在處理一個任務的整個過程中,只有需要運算的時候CPU才參與運算,其它時候CPU就在空轉,一直到線程處理完;對于多線程,一個線程處理任務過程中,在需要運算時使用CPU運算,其它時候就不占用(異步執行IO操作),讓其它需要進行運算的線程去占用運算,充分利用CPU讓其不停的運算處理。
就好比工人用計算器計算登記貨車運來的貨物(計算器好比CPU,貨車運貨物好比IO流),一個工人在等待運磚塊的貨車,運磚貨車一到,工人便拿起計算器累加計算已到的總磚塊數量,計算登記好后等待下一輛運轉貨車到來,計算器也就放在一旁了,而每個工人職責分明,不會去登記其它貨物,造成計算器資源浪費。如果同時有多個工人進行登記,一個工人計算登記好運磚貨物便釋放計算器并等待下一輛運轉貨車到來;在第一個工人等待過程中,下一個工人可以使用計算器計算登記運沙貨物,登記好后釋放計算器并等待下一輛運沙貨車到來;一直釋放、占用循環下去,充分利用計算器資源。
使用多線程能夠充分利用CPU,看起來像多個任務同時并行接收與執行,但相對于CPU來說任務還是一個一個依次串行處理,并沒有并行執行,只是CPU資源沒有浪費,得到充分利用,效率便上來了。
單核+IO密集型任務場景時,使用異步IO操作時可以考慮使用多線程處理能提高處理效率,在進行異步IO操作時,線程可以釋放CPU;使用同步IO操作時,線程會被阻塞,不會釋放CPU,即使啟動多個線程執行,多個線程也只是同時接收任務,最終任務還是被串行執行,所以使用多線程相比于單線程處理效率并沒有提高,可能還會效率還低一點。
多核 + 計算密集型任務:
在多核情況下,有多個物理核心處理器,多個線程可以分別獲取不同的核心處理器(CPU)同時處理任務。就好比工人使用計算器來記賬,可以為每個工人都分配一個計算器,多個工人同時使用計算器計算加減乘除來獲得結果。
在處理計算密集型任務的時候,使用多個線程可以同時接收多個計算密集型任務并進行運算處理,多個任務并行運算處理,提高整體的執行效率;而如果只使用單線程來處理,任務只能串行處理,一個線程只能使用一個CPU,其它CPU就處于空閑狀態。就好比多個工人都在做記賬任務,每個工人都配備一個計算器,這個時候每個工人可以并行計算記賬,而無需等待。
多核 + 計算密集型任務場景時,使用多線程處理就可以極大提升任務處理效率。
多核 + IO密集型任務:
在處理IO密集型任務的時候,雖然多線程可以分別落在不同的核心處理器(CPU)去處理任務,不管是同步IO還是異步IO操作,多線程下都可以并行執行多個任務,相比于單線程處理效率得到極大提升。對于同步IO和異步IO操作,異步IO操作下可以使更多線程搶占CPU執行,更充分的利用CPU;同步IO操作會浪費大量的CPU資源。
同樣使用工人用計算器計算登記貨車運來的貨物(計算器好比CPU,貨車運貨物好比IO流)的例子。對于同步IO,就好比工人使用完計算器后不給下一個工人使用,一直占有知道所有貨物運完計算登記完為止。那么一個工人使用一個計算器只登記自己負責的貨物線路,多個工人使用多個計算器可以同時并行登記各自負責的貨物線路,任務處理速度是上來了,但浪費了更多的資源。對于異步IO,就好比工人使用完計算器后就釋放出來不占用,讓下一個工人使用。在指定數量的計算器下,就可以有指定數量的工人同時并行計算登記各自的貨物線路,在使用計算器計算完后,釋放計算器,在等待下一輛貨車運貨到來之前,就可以有多個計算器釋放出來讓其它多個工人繼續使用登記,宏觀上看,在指定數量的計算器下,有更多的工人同時計算登記,這樣不僅任務處理速度是上來了,而且計算器也能夠得到充分使用。
多核 + IO密集型任務場景時,使用多線程處理就可以極大提升任務處理速度。
附
異步 I/O 和同步 I/O 是兩種不同的 I/O 操作模式,它們在執行過程和效率上有著明顯的差異。
同步 I/O 操作:
- 同步 I/O 操作會阻塞當前線程,直到 I/O 操作完成。
- 在 I/O操作執行期間,當前線程無法處理其他任務,系統的并發能力受限。
- 編程模型相對簡單,代碼結構清晰。
- 適用于 CPU 密集型任務或 I/O操作時間較短的場景。
異步 I/O 操作:
- 異步 I/O 操作不會阻塞當前線程,而是繼續執行其他任務。
- I/O 操作完成時,通過回調函數或事件通知調用者。
- 可以通過多線程同時執行多個異步 I/O 操作,充分利用 CPU 資源,提高 I/O 吞吐量。
- 適用于 I/O 密集型任務,如網絡通信、文件I/O 等,可以提高系統的并發能力和響應性。
- 但是實現異步 I/O 操作需要更復雜的編程模型,增加了代碼的復雜度。
在單核 CPU 情況下,I/O 密集型任務使用同步 I/O 操作時,單線程和多線程的效率對比如下:
單線程同步 I/O 操作:
- 在單核 CPU 上,當執行同步 I/O 操作時,當前線程會被阻塞,無法執行其他任務。
- 整個系統只能順序地執行 I/O 操作,效率較低。
- 當 I/O 操作時間較長時,系統的響應性會大大降低。
多線程同步 I/O 操作:
- 在單核 CPU 上,即使啟動多個線程執行同步 I/O 操作,也只能被串行執行。
- 每個線程在執行 I/O 操作時仍然會被阻塞,無法處理其他任務。
- 線程上下文切換也會帶來一定的性能開銷。
- 因此,多線程并不能提高 I/O 密集型任務在單核 CPU上的效率。