我正在用 Go 做一些實驗,我發(fā)現(xiàn)了一些非常奇怪的東西。當(dāng)我在我的計算機上運行以下代碼時,它會在大約 0.5 秒內(nèi)執(zhí)行。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)}但是,當(dāng)我使用runtime.GOMAXPROCS(1)它執(zhí)行它時,它的執(zhí)行速度要快得多(~0.15 秒)。誰能向我解釋為什么使用更多內(nèi)核運行許多 goroutine 會變慢?將 goroutine 復(fù)用到多個核心上是否有任何顯著的開銷?我意識到 goroutines 沒有做任何事情,如果我不得不等待例程真正做一些事情,那可能會是另一回事。
2 回答

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

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