为了账号安全,请及时绑定邮箱和手机立即绑定

为什么多核上的 goroutine 分配速度较慢?

为什么多核上的 goroutine 分配速度较慢?

Go
手掌心 2021-06-02 14:20:53
我正在用 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在两种情况下运行该程序,看看它的行为有何不同。


查看完整回答
反对 回复 2021-06-07
?
慕尼黑5688855

TA贡献1848条经验 获得超2个赞

除非您有大量的工作负载可以从多核上工作而受益,否则测量多核上的性能总是很困难的。问题是代码需要在线程和内核之间共享,这意味着虽然可能不会有巨大的开销,但仍然有很大的开销,特别是对于简单的代码,降低了整体性能。

就像你提到的那样,如果你做了一些 CPU 密集型的事情,那将是一个完全不同的故事。



查看完整回答
反对 回复 2021-06-07
  • 2 回答
  • 0 关注
  • 238 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信