Go Runtime(八):Channel与Select
本文源码基线为 Go 1.26.2、Linux/amd64。Channel 的语言语义跨平台一致;文中的字段、函数和行号固定到该版本,后续版本可能调整实现。 Channel 不是“带锁队列”的同义词。它同时实现值传递、goroutine 阻塞与唤醒、close 广播、select 多路竞争,并且要和栈复制、GC、Timer 配合。 理解 Channel 的关键,是区分三种正常数据路径:直接交接、环形缓冲区、等待队列。前两条可以立即完成;进入等待队列才会把当前 G 变为 _Gwaiting。nil Channel 的阻塞操作是没有数据路径的永久 park,属于另一个边界情况。 公开语义与内存模型边界 程序首先依赖的是语言契约,而不是 hchan 的字段。例如下面的读取不需要再给 published 加锁: GOvar published int done := make(chan struct{}) go func() { published = 42 close(done) }() <-done fmt.Println(published) // 42 close(done) synchronized before 因关闭而返回的接收,所以接收之后能够观察到此前对 published 的写入。一般地,一次发送 synchronized before 对应接收完成;对容量为 C 的缓冲 Channel,第 k 次接收 synchronized before 第 k+C 次发送完成;当 C=0 时,还额外有接收发生在对应发送完成之前的保证。 ...