<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Channel on 我的技术博客</title><link>https://buvidk1234.github.io/tags/channel/</link><description>Recent content in Channel on 我的技术博客</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Tue, 18 Aug 2026 00:17:00 +0800</lastBuildDate><atom:link href="https://buvidk1234.github.io/tags/channel/index.xml" rel="self" type="application/rss+xml"/><item><title>Go Runtime（八）：Channel与Select</title><link>https://buvidk1234.github.io/posts/go-runtime-08-channel-select/</link><pubDate>Tue, 18 Aug 2026 00:17:00 +0800</pubDate><guid>https://buvidk1234.github.io/posts/go-runtime-08-channel-select/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源码基线为 &lt;strong&gt;Go 1.26.2、Linux/amd64&lt;/strong&gt;。Channel 的语言语义跨平台一致；文中的字段、函数和行号固定到该版本，后续版本可能调整实现。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Channel 不是“带锁队列”的同义词。它同时实现值传递、goroutine 阻塞与唤醒、&lt;code&gt;close&lt;/code&gt; 广播、&lt;code&gt;select&lt;/code&gt; 多路竞争，并且要和栈复制、GC、race detector、Timer 配合。&lt;/p&gt;
&lt;p&gt;理解 Channel 的关键，是区分三种正常数据路径：直接交接、环形缓冲区、等待队列。前两条可以立即完成；进入等待队列才会把当前 G 变为 &lt;code&gt;_Gwaiting&lt;/code&gt;。nil Channel 的阻塞操作是没有数据路径的永久 park，属于另一个边界情况。&lt;/p&gt;
&lt;h2 id="从语法到runtime入口"&gt;从语法到runtime入口&lt;/h2&gt;
&lt;p&gt;编译器把普通发送和接收分别降低为 &lt;code&gt;runtime.chansend1&lt;/code&gt;、&lt;code&gt;runtime.chanrecv1/2&lt;/code&gt;。非阻塞的单 case &lt;code&gt;select&lt;/code&gt; 会被优化为 &lt;code&gt;selectnbsend&lt;/code&gt; 或 &lt;code&gt;selectnbrecv&lt;/code&gt;；多个有效 case 才构造 case 数组并调用 &lt;code&gt;runtime.selectgo&lt;/code&gt;。&lt;/p&gt;
&lt;details class="code-fold" open&gt;
&lt;summary&gt;GO&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// runtime.chansend1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// runtime.chanrecv1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// runtime.chanrecv2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// runtime.closechan&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;
&lt;p&gt;这意味着 &lt;code&gt;select&lt;/code&gt; 不是对每个 case 依次执行一次普通 channel 操作。它必须在所有相关 Channel 锁的保护下完成一次原子决策。&lt;/p&gt;
&lt;p&gt;源码入口：&lt;a href="https://github.com/golang/go/blob/go1.26.2/src/cmd/compile/internal/walk/select.go#L56"&gt;&lt;code&gt;walk/select.go&lt;/code&gt;&lt;/a&gt; 与 &lt;a href="https://github.com/golang/go/blob/go1.26.2/src/runtime/chan.go#L159"&gt;&lt;code&gt;chan.go&lt;/code&gt;&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id="hchan保存什么"&gt;hchan保存什么&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/golang/go/blob/go1.26.2/src/runtime/chan.go#L34"&gt;&lt;code&gt;hchan&lt;/code&gt;&lt;/a&gt; 是 Channel 的运行时对象：&lt;/p&gt;</description></item></channel></rss>