goroutine 泄漏不一定忘了 cancel:还要看 sender 和 receiver 谁没回家
goroutine 泄漏最讨厌的地方,不是它会炸,而是它不炸。
它先是悄悄多几个,再多几十个,最后把内存、延迟、CPU 一起拖下水。你回头看日志,发现代码没报错;你再看监控,发现曲线只是在往上爬。
很多人看到这种情况,第一反应是:是不是忘了 …
goroutine 泄漏最讨厌的地方,不是它会炸,而是它不炸。
它先是悄悄多几个,再多几十个,最后把内存、延迟、CPU 一起拖下水。你回头看日志,发现代码没报错;你再看监控,发现曲线只是在往上爬。
很多人看到这种情况,第一反应是:是不是忘了 …
goroutine 从 200 慢慢涨到 2 万,线上服务还没挂,但你知道它不对劲。
监控图上那条线不陡,甚至有点温和。它不像事故,更像一个迟早会来的事故。
这时候很多人的第一反应是:把 channel buffer 调大一点。 …
代码评审里经常出现这种争论:一个 goroutine 写完结果,close(done);另一个 goroutine 等 <-done 再读结果。有人看着觉得多此一举:这不就是通知一下吗?换成一个 bool,或者 sleep 一小会儿, …
线上最烦的并发 bug,往往不是崩得轰轰烈烈,而是偶尔读到一个不该出现的旧值。
配置已经加载了,日志也打了“ready”,另一个 goroutine 却像没看见一样,读到的还是旧数据。你盯着代码看半天,越看越觉得冤:明明是先写数据,再把 …
很多人写 select,脑子里都有一个抽奖箱。
几个 case 往里一扔,runtime 随机摸一个。哪个 channel 先 ready,哪个就中;都没 ready,就看 default;没有 default,就等。
这个理解不能说全错, …
线上最烦的 channel 问题,往往不是“发不出去”。
而是你以为自己在等一个值,结果等来的是零值;你以为 close(ch) 只是关门,结果它把一批阻塞的 goroutine 全部叫醒;你以为 nil channel 和 closed …
goroutine dump 里刷出一排 [chan send],你知道它卡住了。
但更麻烦的问题是:它到底卡在哪?
是 channel 本身是 nil?是已经有人在等接收,只差一次交付?是 buffer 满了?还是它已经被 runtime …
接口超时了,goroutine 曲线还在往上爬。
日志里已经打出 context deadline exceeded,调用方也早就不等了。你盯着监控看了十分钟,心里开始冒出那个判断:是不是 context.WithTimeout 没生效? …
上一篇讲到最后,其实只把问题说完了一半。
如果你面对的是任务、结果、信号和访问权交接,channel 确实比 mutex 更顺手。它能把 goroutine 之间的关系写出来,让代码不只是在“保护状态”,而是在表达一段通信。
但很多 …
上一篇说到一个很典型的场景:为了写得“更 Go”,有人把一个普通 cache 写成了小型 RPC。
锁确实没了。
但你多了 request、reply channel、owner goroutine、退出顺序、取消处理。读一个 map,本来 …
有些 Go 代码,一看就知道作者很努力。
为了让一个普通 cache 看起来“更 Go”,他把 sync.RWMutex 拿掉了,换成一个专门的 goroutine 来“拥有”这份状态。每次 Get,调用方先构造 request,发进 …
线上偶现一个很烦的 bug:配置已经加载了,日志也打印了“ready”,但另一个 goroutine 读到的还是旧值。
代码看起来没什么毛病:先写数据,再把 ready 置成 true。读的一侧先等 ready,再读数据。人脑看这段逻辑,很 …
goroutine 数量从 200 慢慢涨到 2 万。
监控图上那条线,不陡,但一直在爬。就像水龙头没拧紧——不喷,但也不会停。
你的第一反应是什么?
加大 buffer。
make(chan int, 100) 改成 make(chan …