如何从一个知识点获得源码层面的理解
来源:1-4 Go 程序是怎么跑起来的
快哉快哉
2021-05-16 00:48:58
经验已经告诉我执行下面的代码会阻塞主进程,然后会报错all goroutines are asleep - deadlock!
package main
func main() {
ch1 := make(chan string)
ch1 <- "hello"
}
但是就是好奇,
all goroutines are asleep - deadlock!
// Check for deadlock situation.
// The check is based on number of running M's, if 0 -> deadlock.
// sched.lock must be held.
func checkdead() {
// For -buildmode=c-shared or -buildmode=c-archive it's OK if
// there are no running goroutines. The calling program is
// assumed to be running.
if islibrary || isarchive {
return
}
...
...
...
// There are no goroutines running, so we can look at the P's.
for _, _p_ := range allp {
if len(_p_.timers) > 0 {
return
}
}
getg().m.throwing = -1 // do not dump full stacks
unlock(&sched.lock) // unlock so that GODEBUG=scheddetail=1 doesn't hang
throw("all goroutines are asleep - deadlock!")
}
但看到这些,毫无头绪从哪里看起,所以向问问曹大,当年读源码的经验?,指点一二。
2回答
首先要有一个宏观的理解,比如就是第一课讲的,知道整个 Go 底层就是一堆线程在不停地执行调度循环
然后在日常碰到问题的时候,再去看详细的实现。
比如你这里的 checkdead:
搜索代码以后发现是在 sysmon 里,通过课程中讲的内容,知道 sysmon 是后台高优先级的一个监控线程,负责干什么事情
然后看 checkdead 的注释,写的是检查是不是目前所有的线程都被阻塞住,那就大概了解这个流程了
有宏观的认识,再去填充细节,我个人认为这样是比较好的
不过 checkdead 这个流程在我们写服务的时候基本上没啥用
Xargin
2021-05-16
第一节课讲了调度循环,了解了调度循环的流程,你对整体的运行框架应该就有了基础的理解
碰到问题的时候,像你这里说的 checkdead,你只要看看 checkdead 是在哪个阶段被调用的,它的功能是什么,再简单画一下图就理解了。
我看 checkdead 的时候,感觉他的注释写的还挺清楚的
中间我看看要不要讲讲怎么读 Go 的底层代码,里面其实有很多代码是可以忽略不读的,特别是一些 if raceenable,traceenable 或者你这里前几行 c-shared,library 之类的,可以先跳过的
相似问题