Go: g0, 特殊的goroutine

发布于: 17 小时前
Go: g0, 特殊的goroutine

ℹ️本文基于Go 1.13

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

调度协程

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

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

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

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

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

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

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

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

v := <-ch

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

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

职责范围

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

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

  • Defer方法分配。

  • Gc操作,例如stw,扫描goroutine的栈以及一些标清操作。

  • 栈增长。 在需要时,Go会增加goroutine的大小。 该操作由g0在prolog方法中完成。

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

本文编译自 Go: g0, Special Goroutine

本文首发于我的公众号:

发布于: 17 小时前 阅读数: 7
用户头像

陈思敏捷

关注

多动脑不痴呆 2017.12.21 加入

gopher

评论

发布
暂无评论
Go: g0, 特殊的goroutine