16

Go: g0, 特殊的goroutine

 3 years ago
source link: http://mp.weixin.qq.com/s?__biz=Mzg2NTA2NzQ2Nw%3D%3D&%3Bmid=2247483873&%3Bidx=1&%3Bsn=724560a071a4ca6b620837d05e29a54e
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

:information_source:  本文基于Go 1.13

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

调度协程

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

YRNBVnu.png!web

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

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

ch := make(chan int)

[...]

ch <- v

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

6nmueyR.png!web

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

reENVbe.png!web

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

NfmuMf2.png!web

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

v := <-ch

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

A3auie7.png!web

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

职责范围

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

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

qQZ7RzQ.png!web

  • Defer方法分配。

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

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

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

编译整理自  Go: g0, Special Goroutine

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

rmErYvQ.png!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK