Go 協程爲什麼比進程和線程佔用的系統資源低?
01 介紹
進程是一個可執行程序在運行時的一塊獨立的虛擬內存 [1] 空間,Linux 給每個進程分配一個虛擬內存空間,包括棧空間、未使用內存、堆空間、BSS、DATA、TEXT 等。
線程可以理解爲輕量級進程,多個線程 “寄生” 在一個進程中,每個線程有獨立的棧空間,其它虛擬內存空間,多個線程共享,所以線程之間通信比較簡單,也就是說線程之間可以通過共享內存通信。
進程和線程都是 CPU 的一個執行單元,在內核態切換,切換成本較高。
協程是用戶態的一個僞執行單元,在用戶態切換執行流程,切換成本較低。
02 切換執行單元的成本
我們通過介紹線程和協程的切換流程,講述爲什麼在內核態切換的成本較高,而在用戶態切換的成本較低?
因爲進程和線程都是內核態切換,並且進程切換成本比線程切換成本更高,所以只介紹線程切換和協程切換的切換成本。
內核態切換 - 線程
在瞭解線程在內核態切換之前,我們先了解一下什麼是 CPU 時間片 [2],在操作系統中,我們會安裝很多軟件,並且我們會同時使用多個軟件,而 CPU 資源有限。
爲了讓多個軟件可以在操作系統中同時運行,CPU 分成一個個的時間片,在每個時間片中運行一個軟件的一個線程,因爲時間片非常短,所以我們會感覺多個軟件在同時運行。
在編寫代碼時,我們爲了可以讓程序被分配到更多的 CPU 資源,可以多創建一些線程,用於提升程序運行的效率。需要注意的是,線程並不是創建越多越好。
因爲 CPU 在內核態切換執行單元(線程)時,會有時間成本,在進行切換執行單元時,需要保存寄存器中的數據,將原執行單元的狀態保存,切換操作也會佔用 CPU 資源(時間片),從而減少了供線程運行的 CPU 資源(時間片)。
除了時間成本之外,還會有性能開銷,系統內核調度線程,需要用戶空間和內核空間切換,因爲只有擁有最高權限的內核空間纔可以調度線程,限於篇幅,我們不再展開敘述。
用戶態切換 - 協程
因爲通過創建線程(執行單元),爲程序爭取更多的 CPU 資源,在線程切換時也會浪費 CPU 資源(時間成本),所以可以將執行單元不再在內核態運行,改爲在用戶態運行,也就是協程。
協程的切換成本較低,是因爲切換比較簡單,並且是在用戶態進行切換,切換的時間成本較低(納秒級),只需將當前協程的 CPU 寄存器的狀態先保存起來,然後將需要 CPU 資源的協程的 CPU 寄存器的狀態加載到 CPU 寄存器中。
關於 Go 協程的調度,我們在之前的文章中介紹過,此處不再贅述。
03 內存佔用
除了 CPU 資源有限之外,內存資源也是有限的,所以我們還需要了解進程、線程、協程的內存佔用。
讀者朋友們應該知道 32 位操作系統只支持 4G 內存的內存條,這是因爲進程在 32 位操作系統中最多隻能佔用 4G 內存,而在 64 位操作系統中可以佔用更多內存。
線程佔用內存一般是 10MB,不同的操作系統版本之間有些差異,區間在 4M - 64M。
協程佔用內存最小,一個協程佔用 2KB 左右的內存。
04 總結
本文我們主要介紹爲什麼 Go 協程比進程和線程佔用的系統資源低,通過進程、線程、協程的 CPU 資源和內存佔用的比較,發現無論是在切換時消耗的 CPU 資源(時間片),還是內存佔用,Go 協程都有明顯優勢。
一句話總結就是 Go 協程的切換成本和內存佔用比線程和進程都低。
需要注意的是,Go 協程佔用系統資源低,並不代表可以無限創建 Go 協程。
參考資料
-
http://www.cs.rpi.edu/academics/courses/fall04/os/c12/
-
https://www.geeksforgeeks.org/time-slicing-in-cpu-scheduling/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/fnFj6Wf_jbDEsm68diRvMw