前几天在读者交流群里看到一位小伙伴,发出了一个致命提问,那就是:“单机的 goroutine 数量控制在多少比较合适?”。
也许你和群内小伙伴第一反应一样,会答复 “控制多少,我觉得没有定论”。
紧接着延伸出了更进一步的疑惑:“goroutine 太多了会影响 gc 和调度吧,主要是怎么预算这个数是合理的呢?”
这是本文要进行探讨的主体,因此本文的结构会是先探索基础知识,再一步步揭开,深入理解这个问题。
Goroutine 是什么
Go 语言作为一个新生编程语言,其令人喜爱的特性之一就是 goroutine。Goroutine 是一个由 Go 运行时管理的轻量级线程,一般称其为 “协程”。
- go f(x, y, z)
操作系统本身是无法明确感知到 Goroutine 的存在的,Goroutine 的操作和切换归属于 “用户态” 中。
Goroutine 由特定的调度模式来控制,以 “多路复用” 的形式运行在操作系统为 Go 程序分配的几个系统线程上。
同时创建 Goroutine 的开销很小,初始只需要 2-4k 的栈空间。Goroutine 本身会根据实际使用情况进行自伸缩,非常轻量。
- func say(s string) {
- for i := 0; i < 9999999; i++ {
- time.Sleep(100 * time.Millisecond)
- fmt.Println(s)
- }
- }
- func main() {
- go say("煎鱼")
- say("你好")
- }
人称可以开几百几千万个的协程小霸王,是 Go 语言的得意之作之一。
调度是什么
既然有了用户态的代表 Goroutine,操作系统又看不到他。必然需要有某个东西去管理他,才能更好的运作起来。
这指的就是 Go 语言中的调度,最常见、面试最爱问的 GMP 模型。因此接下来将会给大家介绍一下 Go 调度的基础知识和流程。
下述内容摘自煎鱼和 p 神写的《Go 语言编程之旅》中的章节内容。