Go: g0——特殊的 goroutine g0, Special Goroutine

本文基于 Go 1.13

Go 中创造所有的 goroutine 都是由内部的调度器管理。Go 调度器会尝试为所有 goroutine 分配运行时间,并在当前 goroutine 被阻止或终止时使所有 CPU 忙于运行 goroutine。 它实际上是作为特殊的 goroutine 运行的。

调度 goroutine

Go 通过GOMAXPROCS变量限制了运行的系统线程数。 这意味着 Go 必须在每个正在运行的线程上调度和管理 goroutine。 该角色被委派给名为g0的特殊 goroutine,这是为每个系统线程创建的第一个 goroutine:

然后,它将安排就绪的 goroutine 在系统线程上运行。

建议阅读文章“ Go:Goroutine,OS 线程和 CPU 管理[1]”,来了解更多关于 PMG 模型的信息。

为了更好地了解在g0上的调度方式,让我们回顾一下通道的使用情况。 这是当 goroutine 阻塞在通道上发送时:

ch := make(chan int)
[...]
ch <- v

在通道上阻塞时,当前 goroutine 将被停放,即处于等待模式,并且不会在任何 goroutine 队列中被推送:

然后,g0替换 goroutine 并进行第一轮调度:

在调度期间,本地队列拥有优先级,并且 goroutine#2 现在将运行:

建议阅读文章“ Go: Go 调度器中的工作窃取(Work-Stealing)[2]” 来了解更多关于调度优先级的细节。

一旦接收器将读取通道,则 goroutine#7 将被解除阻塞:

v := <-ch

接收到消息的 goroutine 将切换到g0并通过将其放置在本地队列中来解锁停放的 goroutine:

特殊的 goroutine 除了管理调度,它还有更多的职责。

职责

与一般 goroutine 相反,g0拥有固定的较大的栈。 这样,Go 可以在需要更大栈并且在不希望栈增长的情况下执行操作。 在g0的职责中,我们可以列出:

  • Goroutine 创建。 当调用go func(){ ... }()go myFunction()时,Go 会将函数创建委托给g0,然后再将其放置在本地队列中。新创建的 goroutine 优先运行,并放置在本地队列的顶部。

建议阅读文章“Go:并发与调度器亲和性( Go: Concurrency & Scheduler Affinity )[3]”了解更多关于 Goroutine 优先级的信息。

  • Defer 方法分配。
  • Gc 操作,例如 stw,扫描 goroutine 的栈以及一些标清操作。
  • 栈增长。 在需要时,Go 会增加 goroutine 的大小。 该操作由g0在 prolog 方法中完成。

这个特殊的 goroutine g0涉及许多其他操作(大量分配,cgo 等),使我们的程序可以更高效地管理操作,并且需要更大的栈,以保持我们的程序在低内存下更加高效。


原文来自: https://medium.com/a-journey-with-go/go-g0-special-goroutine-8c778c6704d8

作者:Vincent Blanchon[4]译者:dust347[5]校对:polaris1119[6]

未经允许随便转载:看过够 » Go: g0——特殊的 goroutine g0, Special Goroutine

赞 (0) 打赏

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏