本篇内容主要讲解“Go语言怎么实现stop the world”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Go语言怎么实现stop the world”吧!
停止世界(Stop the world)
停止程序意味着停止所有正在运行的 goroutine。下面是一个执行 STW 的简单程序:
func main() { runtime.GC() }
运行垃圾回收器,将触发 STW 两个阶段。
有关垃圾回收器周期的更多信息,建议阅读我的另外一篇文章 “Go:垃圾收集器如何标记内存? ① ”
第一步:抢占所有正在运行的 goroutine:
goroutine 抢占
一旦 goroutine 被抢占,它们将在安全点停止。同时,P 处理器将(正在运行的代码或在空闲列表)被标记为已停止,以不运行任何代码:
P 标记为已停止
然后,Go 调度程序将运行,将每个 M 与其 P 各自分离,并将其放入空闲列表中:
M 已移至闲置清单
关于在每个上运行的 goroutine M,它们将在全局队列中等待:
Goroutine 在全局队列中等待
然后,一旦世界停止了,只有唯一活动的 goroutine 才能安全地运行,并在工作完成后启动整个世界。下面跟踪图将有助于理解此阶段发生在何时:
跟踪 “ STW”阶段
系统调用
“STW”阶段也可能会影响系统调用,因为它们可能会在 STW 时返回。让我们以一个密集执行系统调用的例子,并查看其如何处理:
func main() { var wg sync.WaitGroup wg.Add(10) for i := 0; i < 10; i++ { go func() { http.Get(`https://httpstat.us/200`) wg.Done() }() } wg.Wait() }
这是跟踪:
STW 阶段,系统调用正在结束。但是,由于没有可用 P(如上一节所述,它们都被标记为已停止),goroutine 将被放入全局队列,并在世界恢复时稍后运行。
延迟时间
“STW” 第三步涉及将所有 M 与其 P 分离。但是,Go 将等待它们自行停止:在调度程序运行时,在 syscall 调用中等。等待 goroutine 被抢占应该很快,但是在某些情况下,可能会导致某些延迟。让我们以一个极端的情况为例:
func main() { var t int for i := 0;i < 20 ;i++ { go func() { for i := 0;i < 1000000000 ;i++ { t++ } }() } runtime.GC() }
在这里,“ Stop the World”阶段需要 2.6 秒:
到此,相信大家对“Go语言怎么实现stop the world”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/209029.html