golang开发中的小故事

本文主要记录在golang学习的过程中看到的或者自己经历的golang开发中觉得比较有意思的小故事,会持续更新

一个有趣的小细节(转载,原文在这里)

先看一段代码

package main

import (
    "fmt"
    "runtime"
)

func main() {
    var i byte
    go func() {
        for i = 0; i <= 255; i++ {
        }
    }()
    fmt.Println("Dropping mic")
    // Yield execution to force executing other goroutines
    runtime.Gosched()
    runtime.GC()
    fmt.Println("Done")
}

首先来说一下结论,这段代码会卡死,毋庸置疑。总结原因总有两点,一个是goroutine中的for循环由于byte的存储设计永远不会大于255,相当于是死循环,所以一旦进入就不会自动停止;第二个原因是runtime.GC()会调用stw暂停所有的goroutine,而本文中for的goroutine永远不会停止,所以卡死(stw只会关闭空闲的p,然后等待忙碌的p)。这个点我认为跟Gosched()关系不大,事实上这句话只关系着goroutine开始的时间,因为gc在关闭goroutine时一定会切换到goroutine,或者说它暂停了mian的goroutine自动会切换到for的goroutine,所以Gosched在这里并没有特别关键的作用。

如果我们往下进一步去改造这段代码,比如在for循环里面加一句print操作,会发现这时候程序就可以正常退出了,这个是因为当io缓冲满了需要输出到stdout时会阻塞for的goroutine,此时这个goroutine就处于空闲状态了。发现这里的本质了么,就是在gc生效陷入等待以后要想办法让for暂停下来,转给io是一个方法,调用Gosched放弃CPU也是一个办法,只要让系统认为它是空闲等待或阻塞状态即可。

然后我们回归这个问题的本质,gc触发stw机制会暂停所有空闲或等待阻塞的goroutine,等待忙碌的goroutine自动完成,或自动暂停,如果不会,则陷入卡死,除了GC意外,事实上runtime.GOMAXPROCS()也会触发stw。

你可能感兴趣的:(golang学习的那些事,golang,gc,stw)