全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-13 7 分钟 ✍️ juanwangdev

Go channel类型与通信详解

Channel实现goroutine间安全通信,遵循"不要通过共享内存通信,而是通过通信共享内存"。

Channel类型

无缓冲channel

Go
// 创建无缓冲channel
ch := make(chan int)

// 特性:
// - 发送必须等待接收
// - 接收必须等待发送
// - 同步语义强

有缓冲channel

Go
// 创建有缓冲channel
ch := make(chan int, 3)

// 特性:
// - 缓冲未满时可异步发送
// - 缓冲非空时可异步接收
// - 缓冲满时发送阻塞
// - 缓冲空时接收阻塞
类型发送条件接收条件用途
无缓冲有人接收有人发送同步
有缓冲缓冲不满缓冲不空数据传递

Channel方向

双向channel

Go
// 默认双向
ch := make(chan int)

// 可发送也可接收
ch <- 1
v := <-ch

单向channel

Go
// 只发送channel
var sendOnly chan<- int = ch

// 只接收channel
var recvOnly <-chan int = ch

// 用于函数参数限制方向
func sender(ch chan<- int) {
    ch <- 1  // 只能发送
}

func receiver(ch <-chan int) {
    v := <-ch  // 只能接收
}

Channel通信操作

发送数据

Go
ch := make(chan int, 2)

ch <- 1  // 发送成功(缓冲未满)
ch <- 2  // 发送成功
ch <- 3  // 阻塞(缓冲满,等待接收)

接收数据

Go
v := <-ch           // 推入变量
fmt.Println(<-ch)   // 直接使用
<-ch                // 丢弃值

// 检查channel状态
v, ok := <-ch
if ok {
    fmt.Println("收到:", v)
} else {
    fmt.Println("channel已关闭")
}

遍历channel

Go
// range自动接收直到关闭
for v := range ch {
    fmt.Println(v)
}
// channel关闭时自动退出

Channel关闭

关闭语法

Go
ch := make(chan int, 5)

ch <- 1
ch <- 2
close(ch)  // 关闭channel

关闭后的行为

Go
// 发送:panic
ch <- 3  // panic: send on closed channel

// 接收:返回零值和false
v, ok := <-ch  // v=0, ok=false

// 再次关闭:panic
close(ch)  // panic: close of closed channel

关闭规则

Go
// 规则:
// 1. 只有发送者关闭
// 2. 不要关闭已关闭的channel
// 3. 接收者不要关闭

// 正确示例
func producer(ch chan<- int) {
    for i := 0; i < 10; i++ {
        ch <- i
    }
    close(ch)  // 发送者关闭
}

func consumer(ch <-chan int) {
    for v := range ch {  // 自动处理关闭
        fmt.Println(v)
    }
}

nil channel行为

nil channel特性

Go
var ch chan int  // nil channel

// 发送:永久阻塞
ch <- 1  // 永久阻塞

// 接收:永久阻塞
<-ch  // 永久阻塞

// 关闭:panic
close(ch)  // panic: close of nil channel

利用nil channel

Go
// 在select中禁用channel
var ch1, ch2 chan int

for {
    select {
    case v := <-ch1:  // ch1=nil时阻塞,不执行
        process1(v)
    case v := <-ch2:
        process2(v)
    }

    // 动态设置ch1/ch2为nil或有效channel
    // 实现动态启用/禁用case
}

Channel容量选择

容量为0

Go
ch := make(chan int)
// 同步语义:发送和接收必须同时就绪
// 适用:同步信号、握手

容量为1

Go
ch := make(chan int, 1)
// 一次异步传递
// 适用:结果缓存、单次通知

容量大于1

Go
ch := make(chan int, 100)
// 批量数据传递
// 适用:worker pool、pipeline

通信语义对比

操作无缓冲有缓冲(未满)有缓冲(满)已关闭
发送阻塞等待立即成功阻塞等待panic
接收阻塞等待立即成功立即成功返回零值

常见用法示例

同步信号

Go
done := make(chan struct{})

go func() {
    time.Sleep(1 * time.Second)
    done <- struct{}{}  // 通知完成
}()

<-done  // 等待完成

数据传递

Go
ch := make(chan int, 10)

go func() {
    for i := 0; i < 10; i++ {
        ch <- i  // 发送数据
    }
    close(ch)
}()

for v := range ch {  // 接收数据
    fmt.Println(v)
}

单向channel限制

Go
func pipeline(in <-chan int, out chan<- int) {
    for v := range in {
        out <- v * 2
    }
}

要点总结

  • 无缓冲channel同步强,发送等待接收
  • 有缓冲channel异步传递,缓冲满才阻塞
  • 双向channel可发可收,单向channel限制方向
  • 只有发送者关闭channel
  • 关闭后发送panic,接收返回零值+false
  • nil channel在select中永久阻塞(可禁用case)
  • range遍历自动处理关闭
  • 用容量0同步,容量>0传递数据

📝 发现内容有误?点击此处直接编辑

← 上一篇 Go Goroutine与并发模型详解
下一篇 → Go goroutine基本概念与创建
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库