会诱发 Goroutine 挂起的 27 个原因

上个月面向读者的提问,我们针对 goroutine 泄露中都会看到的大头 runtime.gopark 函数进行了学习和了解,输出了 《Goroutine 一泄露就看到他,这是个什么?》。

有小伙伴提到,虽然我们知道了 runtime.gopark 函数的缘起和内在,但其实没有提到 runtime.gopark 的诱发原因,毕竟他会导致 Goroutine 挂起,这是我们日常编码中需要关注的

为此我整理了一下笔记,今天这篇文章就和大家一起围观 gopark 的 27 个诱发原因。为了方便阅读,我们会根据分类进行说明。

第一部分

标识含义
waitReasonZero
waitReasonGCAssistMarkingGC assist marking
waitReasonIOWaitIO wait
  • waitReasonZero:无正式解释,从使用情况来看。主要在 sleep 和 lock 的 2 个场景中使用。

  • waitReasonGCAssistMarking:GC 辅助标记阶段会使得阻塞等待。

  • waitReasonIOWait:IO 阻塞等待时,例如:网络请求等。

第二部分

标识含义
waitReasonChanReceiveNilChanchan receive (nil chan)
waitReasonChanSendNilChanchan send (nil chan)
  • waitReasonChanReceiveNilChan:对未初始化的 channel 进行读操作。

  • waitReasonChanSendNilChan:对未初始化的 channel 进行写操作。

第三部分

标识含义
waitReasonDumpingHeapdumping heap
waitReasonGarbageCollectiongarbage collection
waitReasonGarbageCollectionScangarbage collection scan
  • waitReasonDumpingHeap:对 Go Heap 堆 dump 时,这个的使用场景仅在 runtime.debug 时,也就是常见的 pprof 这一类采集时阻塞。

  • waitReasonGarbageCollection:在垃圾回收时,主要场景是 GC 标记终止(GC Mark Termination)阶段时触发。

  • waitReasonGarbageCollectionScan:在垃圾回收扫描时,主要场景是 GC 标记(GC Mark)扫描 Root 阶段时触发。

第四部分

标识含义
waitReasonPanicWaitpanicwait
waitReasonSelectselect
waitReasonSelectNoCasesselect (no cases)
  • waitReasonPanicWait:在 main goroutine 发生 panic 时,会触发。

  • waitReasonSelect:在调用关键字 select 时会触发。

  • waitReasonSelectNoCases:在调用关键字 select 时,若一个 case 都没有,会直接触发。

第五部分

标识含义
waitReasonGCAssistWaitGC assist wait
waitReasonGCSweepWaitGC sweep wait
waitReasonGCScavengeWaitGC scavenge wait
  • waitReasonGCAssistWait:GC 辅助标记阶段中的结束行为,会触发。

  • waitReasonGCSweepWait:GC 清扫阶段中的结束行为,会触发。

  • waitReasonGCScavengeWait:GC scavenge 阶段的结束行为,会触发。GC Scavenge 主要是新空间的垃圾回收,是一种经常运行、快速的 GC,负责从新空间中清理较小的对象。

第六部分

标识含义
waitReasonChanReceivechan receive
waitReasonChanSendchan send
waitReasonFinalizerWaitfinalizer wait
  • waitReasonChanReceive:在 channel 进行读操作,会触发。

  • waitReasonChanSend:在 channel 进行写操作,会触发。

  • waitReasonFinalizerWait:在 finalizer 结束的阶段,会触发。在 Go 程序中,可以通过调用 runtime.SetFinalizer 函数来为一个对象设置一个终结者函数。这个行为对应着结束阶段造成的回收。

第七部分

标识含义
waitReasonForceGCIdleforce gc (idle)
waitReasonSemacquiresemacquire
waitReasonSleepsleep
  • waitReasonForceGCIdle:强制 GC(空闲时间)结束时,会触发。

  • waitReasonSemacquire:信号量处理结束时,会触发。

  • waitReasonSleep:经典的 sleep 行为,会触发。

第八部分

标识含义
waitReasonSyncCondWaitsync.Cond.Wait
waitReasonTimerGoroutineIdletimer goroutine (idle)
waitReasonTraceReaderBlockedtrace reader (blocked)
  • waitReasonSyncCondWait:结合 sync.Cond 用法能知道,是在调用 sync.Wait 方法时所触发。

  • waitReasonTimerGoroutineIdle:与 Timer 相关,在没有定时器需要执行任务时,会触发。

  • waitReasonTraceReaderBlocked:与 Trace 相关,ReadTrace会返回二进制跟踪数据,将会阻塞直到数据可用。

第九部分

标识含义
waitReasonWaitForGCCyclewait for GC cycle
waitReasonGCWorkerIdleGC worker (idle)
waitReasonPreemptedpreempted
waitReasonDebugCalldebug call
  • waitReasonWaitForGCCycle:等待 GC 周期,会休眠造成阻塞。

  • waitReasonGCWorkerIdle:GC Worker 空闲时,会休眠造成阻塞。

  • waitReasonPreempted:发生循环调用抢占时,会会休眠等待调度。

  • waitReasonDebugCall:调用 GODEBUG 时,会触发。

总结

今天这篇文章是对开头 runtime.gopark 函数的详解文章的一个补充,我们能够对此了解到其诱发的因素。

主要场景为:

  1. 通道(Channel)。

  2. 垃圾回收(GC)。

  3. 休眠(Sleep)。

  4. 锁等待(Lock)。

  5. 抢占(Preempted)。

  6. IO 阻塞(IO Wait)

  7. 其他,例如:panic、finalizer、select 等。

我们可以根据这些特性,去拆解可能会造成阻塞的原因。其实也就没必要记了,他们会导致阻塞肯定是由于存在影响控制流的因素,才会导致 gopark 的调用。

活学活用:)

推荐阅读:

如何在测试中发现goroutine泄漏

资料下载

点击下方卡片关注公众号,发送特定关键字获取对应精品资料!

  • 回复「电子书」,获取入门、进阶 Go 语言必看书籍。

  • 回复「视频」,获取价值 5000 大洋的视频资料,内含实战项目(不外传)!

  • 回复「路线」,获取最新版 Go 知识图谱及学习、成长路线图。

  • 回复「面试题」,获取四哥精编的 Go 语言面试题,含解析。

  • 回复「后台」,获取后台开发必看 10 本书籍。

对了,看完文章,记得点击下方的卡片。关注我哦~ 👇👇👇

如果您的朋友也在学习 Go 语言,相信这篇文章对 TA 有帮助,欢迎转发分享给 TA,非常感谢!2efc1ec1b9f8330f04acdc79131670d0.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值