<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Runtime on Zampo Blog</title><link>https://blog.cpdd.fyi/tags/runtime/</link><description>Recent content in Runtime on Zampo Blog</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Thu, 21 May 2026 15:17:00 +0800</lastBuildDate><atom:link href="https://blog.cpdd.fyi/tags/runtime/index.xml" rel="self" type="application/rss+xml"/><item><title>Go channel 源码不是在讲队列，而是在讲 goroutine 怎么排队</title><link>https://blog.cpdd.fyi/posts/go-channel-hchan-runtime-source/</link><pubDate>Thu, 21 May 2026 15:17:00 +0800</pubDate><guid>https://blog.cpdd.fyi/posts/go-channel-hchan-runtime-source/</guid><description>&lt;p&gt;goroutine dump 里满屏 &lt;code&gt;chan send&lt;/code&gt;，你知道它卡住了。&lt;/p&gt;
&lt;p&gt;但它到底卡在哪里？&lt;/p&gt;
&lt;p&gt;是缓冲区满了？没有 receiver？被 &lt;code&gt;select&lt;/code&gt; 挂进了等待队列？还是 channel 被 close 之后才醒过来，然后 panic？&lt;/p&gt;
&lt;p&gt;如果只停留在“channel 是 goroutine 之间通信的管道”，这些问题永远说不清。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ch &amp;lt;- v&lt;/code&gt; 这一行代码，在 Go runtime 里不是一句“把数据塞进队列”。它会走过 &lt;code&gt;hchan&lt;/code&gt;、环形缓冲区、&lt;code&gt;sendq&lt;/code&gt; / &lt;code&gt;recvq&lt;/code&gt;、&lt;code&gt;sudog&lt;/code&gt;、&lt;code&gt;gopark&lt;/code&gt;、&lt;code&gt;goready&lt;/code&gt;，最后决定一个 goroutine 是继续跑，还是挂起来等别人。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.cpdd.fyi/images/go-channel-hchan-runtime-source/cover.png" alt="Go channel hchan 运行时封面"&gt;&lt;/p&gt;
&lt;p&gt;Go 的 channel 设计长期受 CSP 思想影响。Rob Pike 在 Go 早期设计和并发模型传播里反复强调：不要通过共享内存来通信，而要通过通信来共享内存。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.cpdd.fyi/images/go-channel-hchan-runtime-source/rob-pike.jpg" alt="Rob Pike"&gt;&lt;/p&gt;
&lt;p&gt;这句话听起来像哲学，但到了 runtime 里，它会变成很具体的结构：谁在等谁，数据放在哪里，哪个 goroutine 应该被唤醒。&lt;/p&gt;
&lt;p&gt;这篇只做一件事：沿着 Go 1.25.4 的 &lt;code&gt;runtime/chan.go&lt;/code&gt; 和 &lt;code&gt;runtime/select.go&lt;/code&gt;，把 channel 的几条关键路径走一遍。&lt;/p&gt;
&lt;p&gt;不是为了背源码。&lt;/p&gt;
&lt;p&gt;是为了让你下次看到 &lt;code&gt;chan send&lt;/code&gt;、&lt;code&gt;chan receive&lt;/code&gt;、&lt;code&gt;close&lt;/code&gt;、&lt;code&gt;select&lt;/code&gt; 的时候，脑子里有一张清楚的运行时地图。&lt;/p&gt;
&lt;p&gt;channel 不是无锁队列，它是带调度语义的协作原语。&lt;/p&gt;
&lt;h2 id="hchanchannel-在运行时到底长什么样"&gt;hchan：channel 在运行时到底长什么样&lt;/h2&gt;
&lt;p&gt;Go 代码里你写的是：&lt;/p&gt;</description></item></channel></rss>