Golang中为什么goroutine比传统pthread更好用?
Golang中为什么goroutine比传统pthread更好用?
忽略默认栈大小/内存的差异,为什么goroutine比pthread更好?Goroutine仍然会导致大量的上下文切换。如果我运行一个fasthttp服务器,它除了返回200状态码外什么都不做,当我达到每秒~200,000个请求时(8个核心,GOMAXPROCS=8),我看到了~250,000 ctxsw/s(使用vmstat测量)。我听到人们谈论goroutine上下文切换成本更低,但我还没有看到任何数据支持这一点——这一点被证明是真的吗?
tl;dr - 抛开内存不谈(RAM很便宜),goroutine是否比其他语言中映射到pthread的并发模型更好?为什么?
更多关于Golang中为什么goroutine比传统pthread更好用?的实战教程也可以访问 https://www.itying.com/category-94-b0.html
Goroutines 的创建成本更低,且不带有任何操作系统开销。
更多关于Golang中为什么goroutine比传统pthread更好用?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Goroutines 的创建成本更低
确实如此
并且不带来任何操作系统开销。
但这一点对吗?如果我运行一个程序,它只有两个 goroutine,其中一个向通道发送数据,而另一个在无限循环中监听该通道,我观察到数十万次操作系统上下文切换,每次切换平均耗时约两微秒。这与我在 Java 中测量的线程间上下文切换时间相差不大。
我知道普遍共识是 Goroutines 即使有操作系统开销,也非常小,我也希望相信这一点,但这与我测试中观察到的数据不符。
上下文切换并非发生在操作系统中,而是发生在CPU上。
你对此无能为力。
协程之间知道如何通信,调度器也清楚这一点,因此可以基于此知识优化调度。
如果你通过线程/进程间的内存观察来实现这一点,这些知识将不可用,通信对调度器来说是不透明的,调度器将不得不时不时地给每个线程分配一个时间片,结果只是导致线程再次交还时间片(或者如果程序设计得不好,会陷入忙等待)。
// 代码示例:此处可放置Go语言代码
Goroutines 之间知道如何通信,调度器也知道这一点,因此可以基于这些知识优化调度。
对我来说,goroutines 的吸引力似乎在于便利性/内存占用,而不一定是性能的提升,正如 @lutzhorn 所说。我同意,通过 Go 并发提供的通道和其他范式,goroutines 非常直观且易于理解。
在我的 fasthttp 与 Vert.x 的示例中,当我注意到在处理相同吞吐量和执行相同工作时,fasthttp 和 net/http 比 Vert.x/Firenio/Undertow/Wizzardo 执行了(略微)更多的上下文切换,并且当上下文切换被认为是比较 pthreads 和 goroutines 时引用的主要原因时,与 pthreads 相比,goroutines 真的减少了系统 CPU 时间吗?
作为免责声明,我明显更喜欢 goroutines 而不是传统的基于 pthread 的并发模型。它们易于理解和使用,并且每个 goroutine 占用 2KB(相比之下,Java 中每个线程至少占用约 64KB),很难说 goroutines 在客观上不比 pthreads 更好。
但从性能角度来看,忽略 RAM 限制,当 goroutines 在内部使用与基于事件循环的模型类似的、系统调用繁重的范式时,它们真的更好吗?


