Go 源码学习 --- chan
· 阅读需 8 分钟
Channel 是 Go 语言最具标志性的特性之一,它以“不要通过共享内存来通信,而要通过通信来共享内存”的设计哲学,为并发编程提供了简洁、安全的解决方案。本文将从源码层面拆解 Channel 的底层实现,带你理解其核心结构、读写逻辑和关键特性。
一、Channel 核心数据结构
Channel 的底层实现全部封装在 Go 运行时(runtime)中,核心结构体是 hchan(定义在 src/runtime/chan.go),我们先看简化后的关键字段:
type hchan struct {
qcount uint // 队列中已有的元素数量
dataqsiz uint // 环形队列的容量(缓冲区大小)
buf unsafe.Pointer // 指向环形队列的指针
elemsize uint16 // 每个元素的大小
closed uint32 // 标记 channel 是否关闭(0:未关闭,1:已关闭)
elemtype *_type // 元素类型信息(用于类型检查、内存分配)
sendx uint // 发送操作的索引(下一个发送元素的位置)
recvx uint // 接收操作的索引(下一个接收元素的位置)
recvq waitq // 等待接收的 goroutine 队列
sendq waitq // 等待发送的 goroutine 队列
lock mutex // 保护 hchan 所有字段的互斥锁
}
// 等待队列的结构(存储阻塞的 goroutine)
type waitq struct {
first *sudog
last *sudog
}
关键字段解读
- 缓冲区相关:
buf指向环形队列,dataqsiz是缓冲区容量,sendx/recvx分别标记发送/接收的位置,实现环形队列的“先进先出”; - 阻塞队列:
recvq和sendq存储因读写阻塞的 goroutine(封装为sudog结构体),sudog是 goroutine 与同步原语(如 channel、mutex)的关联载体; - 基础属性:
elemsize/elemtype保证类型安全,closed标记关闭状态,lock保证并发访问的原子性。
