我正在用 Go 做一些實驗,我發現了一些非常奇怪的東西。當我在我的計算機上運行以下代碼時,它會在大約 0.5 秒內執行。package mainimport ( "fmt" "runtime" "time")func waitAround(die chan bool) { <- die}func main() { var startMemory runtime.MemStats runtime.ReadMemStats(&startMemory) start := time.Now() cpus := runtime.NumCPU() runtime.GOMAXPROCS(cpus) die := make(chan bool) count := 100000 for i := 0; i < count; i++ { go waitAround(die) } elapsed := time.Since(start) var endMemory runtime.MemStats runtime.ReadMemStats(&endMemory) fmt.Printf("Started %d goroutines\n%d CPUs\n%f seconds\n", count, cpus, elapsed.Seconds()) fmt.Printf("Memory before %d\nmemory after %d\n", startMemory.Alloc, endMemory.Alloc) fmt.Printf("%d goroutines running\n", runtime.NumGoroutine()) fmt.Printf("%d bytes per goroutine\n", (endMemory.Alloc - startMemory.Alloc)/uint64(runtime.NumGoroutine())) close(die)}但是,當我使用runtime.GOMAXPROCS(1)它執行它時,它的執行速度要快得多(~0.15 秒)。誰能向我解釋為什么使用更多內核運行許多 goroutine 會變慢?將 goroutine 復用到多個核心上是否有任何顯著的開銷?我意識到 goroutines 沒有做任何事情,如果我不得不等待例程真正做一些事情,那可能會是另一回事。
2 回答

慕慕森
TA貢獻1856條經驗 獲得超17個贊
在單核上運行時,goroutine 的分配和切換只是內部記賬的問題。Goroutine 永遠不會被搶占,因此切換邏輯非常簡單且非???。更重要的是,在這種情況下,您的主例程根本不會讓步,因此 goroutine 在終止之前甚至不會開始執行。你分配結構然后刪除它,就是這樣。(編輯這對于較新版本的 go 可能不是真的,但它肯定更有序,只有 1 個進程)
但是當你在多個線程上映射例程時,你會突然涉及到操作系統級上下文切換,這會慢幾個數量級,而且更復雜。即使您在多個內核上,還有很多工作要做。另外,現在您的 gouroutine 可能實際上在程序終止之前正在運行。
嘗試strace
在兩種情況下運行該程序,看看它的行為有何不同。

慕尼黑5688855
TA貢獻1848條經驗 獲得超2個贊
除非您有大量的工作負載可以從多核上工作而受益,否則測量多核上的性能總是很困難的。問題是代碼需要在線程和內核之間共享,這意味著雖然可能不會有巨大的開銷,但仍然有很大的開銷,特別是對于簡單的代碼,降低了整體性能。
就像你提到的那樣,如果你做了一些 CPU 密集型的事情,那將是一個完全不同的故事。
- 2 回答
- 0 關注
- 278 瀏覽
添加回答
舉報
0/150
提交
取消