channel 相关知识点
1 type hchan struct { 2 qcount uint // 队列中元素数量 3 dataqsiz uint // 环形队列大小 4 buf unsafe.Pointer // 指向环形队列 5 elemsize uint16 // 元素大小 6 closed uint32 // 关闭标志 7 elemtype *_type // 元素类型 8 sendx uint // 发送索引 9 recvx uint // 接收索引 10 recvq waitq // 接收等待队列 11 sendq waitq // 发送等待队列 12 lock mutex // 互斥锁 13 }
关键操作原理
-
发送流程:
-
加锁保护
-
如果有接收者等待,直接拷贝数据给接收者
-
否则尝试放入缓冲区
-
缓冲区满则加入sendq并挂起
-
-
接收流程:
-
加锁保护
-
如果有发送者等待,直接从发送者获取数据
-
否则尝试从缓冲区获取
-
缓冲区空则加入recvq并挂起
-
// 1. 同步通信(无缓冲) ch := make(chan struct{}) go func() { // ... 工作 ch <- struct{}{} // 发送完成信号 }() <-ch // 等待完成 // 2. 异步通信(有缓冲) ch := make(chan int, 100) go func() { for task := range ch { // 处理任务 } }()
高级模式:
-
// 1. 扇出(一个生产者,多个消费者) func fanOut(in <-chan int, out []chan int) { for v := range in { for _, ch := range out { ch <- v } } } // 2. 扇入(多个生产者,一个消费者) func fanIn(out chan<- int, ins ...<-chan int) { var wg sync.WaitGroup for _, in := range ins { wg.Add(1) go func(in <-chan int) { defer wg.Done() for v := range in { out <- v } }(in) } wg.Wait() } // 3. 超时控制 select { case res := <-ch: fmt.Println(res) case <-time.After(1 * time.Second): fmt.Println("timeout") }
4. Channel 操作特性
操作类型与结果
操作 nil channel closed channel active channel 发送 永久阻塞 panic 阻塞或成功 接收 永久阻塞 不阻塞返回零值 阻塞或成功 关闭 panic panic 成功 select 机制
-
随机选择一个就绪的case执行
-
可设置default避免阻塞
-
典型应用:
-
超时控制
-
非阻塞操作
-
多channel监听
-
5. Channel 常见问题
1. Channel 泄漏
场景:
-
Goroutine阻塞在channel操作无法退出
-
未被引用的channel占用内存
预防:
-
使用context控制退出
-
确保所有Goroutine都有退出路径
-
使用buffered channel减少阻塞
2. Panic 场景
-
关闭nil channel
-
重复关闭channel
-
向已关闭channel发送数据
3. 性能考量
-
无缓冲channel有更高的同步开销
-
大量小对象传输考虑传递指针
-
高并发场景考虑sync.Pool减少分配
6. Channel 与并发控制
并发模式对比
模式 Channel sync.Mutex sync.WaitGroup 数据传递 ✓ ✗ ✗ 状态共享 适合 适合 有限 同步控制 适合 适合 适合 复杂度 中 低 低 选择建议
-
用channel:
-
数据传输
-
事件通知
-
控制流水线
-
-
用锁:
-
保护共享状态
-
精细控制临界区
-
-
用WaitGroup:
-
简单等待任务组完成工作池模式
-
func workerPool(numWorkers int, jobs <-chan int, results chan<- int) { var wg sync.WaitGroup for i := 0; i < numWorkers; i++ { wg.Add(1) go func(id int) { defer wg.Done() for job := range jobs { results <- process(job) // 处理任务 } }(i) } wg.Wait() close(results) }
优雅关闭
-
func runService(stopCh <-chan struct{}) { for { select { case <-stopCh: fmt.Println("shutting down...") return case data := <-inputCh: go handle(data) } } } // 调用方 close(stopCh) // 广播关闭信号
-
-
-

浙公网安备 33010602011771号