Channel操作 #

一、发送操作 #

1.1 基本发送 #

go
ch := make(chan int)
ch <- 42

1.2 阻塞特性 #

go
func main() {
    ch := make(chan int)
    
    go func() {
        time.Sleep(time.Second)
        <-ch  // 接收
    }()
    
    ch <- 1  // 阻塞直到被接收
    fmt.Println("Sent")
}

1.3 缓冲发送 #

go
ch := make(chan int, 2)

ch <- 1  // 不阻塞
ch <- 2  // 不阻塞
// ch <- 3  // 阻塞

二、接收操作 #

2.1 基本接收 #

go
v := <-ch

2.2 检查是否关闭 #

go
v, ok := <-ch
if !ok {
    fmt.Println("Channel closed")
}

2.3 阻塞接收 #

go
func main() {
    ch := make(chan int)
    
    go func() {
        time.Sleep(time.Second)
        ch <- 1
    }()
    
    v := <-ch  // 阻塞直到有数据
    fmt.Println(v)
}

2.4 非阻塞接收 #

go
select {
case v := <-ch:
    fmt.Println(v)
default:
    fmt.Println("No data")
}

三、关闭操作 #

3.1 close函数 #

go
ch := make(chan int)
close(ch)

3.2 关闭后的行为 #

go
ch := make(chan int, 2)
ch <- 1
ch <- 2
close(ch)

fmt.Println(<-ch)  // 1
fmt.Println(<-ch)  // 2
fmt.Println(<-ch)  // 0(零值)

3.3 检测关闭 #

go
for {
    v, ok := <-ch
    if !ok {
        break
    }
    fmt.Println(v)
}

3.4 range遍历 #

go
for v := range ch {
    fmt.Println(v)
}

四、缓冲通道操作 #

4.1 容量管理 #

go
ch := make(chan int, 3)

fmt.Println(cap(ch))  // 3
fmt.Println(len(ch))  // 0

ch <- 1
fmt.Println(len(ch))  // 1

4.2 满与空 #

go
func isFull(ch chan int) bool {
    return len(ch) == cap(ch)
}

func isEmpty(ch chan int) bool {
    return len(ch) == 0
}

4.3 批量处理 #

go
func batchProcess(ch chan int, batchSize int) []int {
    batch := make([]int, 0, batchSize)
    for i := 0; i < batchSize; i++ {
        select {
        case v := <-ch:
            batch = append(batch, v)
        default:
            return batch
        }
    }
    return batch
}

五、单向通道操作 #

5.1 只发送 #

go
func sender(ch chan<- int) {
    for i := 0; i < 10; i++ {
        ch <- i
    }
    close(ch)
}

5.2 只接收 #

go
func receiver(ch <-chan int) {
    for v := range ch {
        fmt.Println(v)
    }
}

5.3 API设计 #

go
type Queue struct {
    ch chan int
}

func (q *Queue) Send() chan<- int {
    return q.ch
}

func (q *Queue) Receive() <-chan int {
    return q.ch
}

六、实际应用 #

6.1 限流器 #

go
func rateLimiter(limit int) chan struct{} {
    ch := make(chan struct{}, limit)
    for i := 0; i < limit; i++ {
        ch <- struct{}{}
    }
    return ch
}

func main() {
    limiter := rateLimiter(10)
    
    for i := 0; i < 100; i++ {
        <-limiter  // 获取令牌
        go func() {
            defer func() { limiter <- struct{}{} }()  // 归还令牌
            // 处理请求
        }()
    }
}

6.2 超时控制 #

go
func withTimeout(ch <-chan int, timeout time.Duration) (int, error) {
    select {
    case v := <-ch:
        return v, nil
    case <-time.After(timeout):
        return 0, errors.New("timeout")
    }
}

6.3 广播 #

go
func broadcast(msg string, subscribers []chan string) {
    for _, ch := range subscribers {
        select {
        case ch <- msg:
        default:
        }
    }
}

6.4 管道 #

go
func pipeline() {
    ch1 := make(chan int)
    ch2 := make(chan int)
    
    go func() {
        for i := 0; i < 10; i++ {
            ch1 <- i
        }
        close(ch1)
    }()
    
    go func() {
        for v := range ch1 {
            ch2 <- v * 2
        }
        close(ch2)
    }()
    
    for v := range ch2 {
        fmt.Println(v)
    }
}

七、常见模式 #

7.1 done通道 #

go
func worker(done chan struct{}) {
    defer close(done)
    // 工作
}

func main() {
    done := make(chan struct{})
    go worker(done)
    <-done
}

7.2 结果通道 #

go
func compute(n int, results chan<- int) {
    results <- n * n
}

func main() {
    results := make(chan int, 10)
    
    for i := 0; i < 10; i++ {
        go compute(i, results)
    }
    
    for i := 0; i < 10; i++ {
        fmt.Println(<-results)
    }
}

7.3 取消通道 #

go
func worker(cancel <-chan struct{}) {
    for {
        select {
        case <-cancel:
            return
        default:
            // 工作
        }
    }
}

八、错误处理 #

8.1 向关闭通道发送 #

go
func safeSend(ch chan int, v int) error {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered:", r)
        }
    }()
    ch <- v
    return nil
}

8.2 关闭已关闭通道 #

go
func safeClose(ch chan int) {
    select {
    case <-ch:
        // 已关闭
    default:
        close(ch)
    }
}

九、最佳实践 #

9.1 明确关闭责任 #

go
func producer(ch chan int) {
    defer close(ch)  // 生产者关闭
    // ...
}

9.2 使用select非阻塞 #

go
select {
case ch <- v:
    // 发送成功
default:
    // 处理缓冲满
}

9.3 合理设置缓冲大小 #

go
ch := make(chan int, runtime.NumCPU()*10)

十、总结 #

Channel操作要点:

操作 说明
发送 ch <- v
接收 v := <-ch
关闭 close(ch)
遍历 for v := range ch

关键点:

  1. 阻塞特性:理解发送和接收的阻塞行为
  2. 缓冲通道:提高性能,减少阻塞
  3. 关闭检测:使用ok值或range检测关闭
  4. 单向通道:提高类型安全性
  5. 错误处理:处理向关闭通道发送的情况

准备好学习Select语句了吗?让我们进入下一章!

最后更新:2026-03-26