當在 Linux 系統上執行lscpu
指令時,它會列出機器上的 CPU 資訊。舉個例子,如果有一個 CPU 具有 2 個核心,且每個核心有兩個執行緒,則表示共有 4 個核心可用。
現在讓我們看看 GoLang 程式會識別多少個核心。
從輸出結果來看,NumCPU
和 GOMAXPROCS
都輸出 4,這是預期的結果。Go 執行時期是如何取得這個資訊的?它是透過類似 lscpu 或 /proc/cpuinfo 的指令取得嗎?讓我們深入研究 GoLang 的原始碼。
在runtime/debug.go
中,它說明這個值來自全域變數ncpu
,這個變數在程序啟動時設定,一旦設定後就不會改變。
ncpu
是在哪裡設定的?在 runtime 目錄中使用 grep 搜尋這個關鍵字,在runtime/os_linux.go
中,有一個函數osinit()
,它呼叫getproccount()
來取得ncpu
的值。
在getproccount()
函數內部,它呼叫sche_getaffinity()
,這個函數會有一個輸出buf
,其中每個值為 1 的位元都會被視為一個核心。
這個函數sche_getaffinity()
是一個使用 Go 組合語言定義的原生函數。其實作可以在runtime/sys_linux_amd64.s
中找到。
從上面可以看出,ncpu
的值與lscpu
的輸出結果並不相同,它是作業系統分配給目前程序的 CPU 數量。在多數情況下,ncpu
的值與作業系統上可用的 CPU 數量相同,這是因為作業系統預設會允許一個程序使用所有可用的 CPU。如果想要限制一個程序使用的 CPU 數量,可以使用來自cgroup
的cpuset
來進行更改。
例如,讓我們建立一個名為gocpu
的 cgroup。
cgcreate -g cpuset:/gocpu
如果想要只允許 cgroup gocpu 使用 CPU 0-1,可以執行
#echo '0' > cpuset.mems
#echo '0-1' > cpuset.cpus
#echo $$ > tasks
然後讓 bash shell 在這個新的 cgroup 中執行,並再次啟動 Go 程式,它現在就只有 2 個核心可以使用了。