编 程 实 战

记录编程学习之路,分享技术实践经验

Go

Go 并发编程深度解析:Goroutine 与 Channel 最佳实践

2026-07-02 · 阅读 3,120 · 作者 编程实战

Go 语言的并发模型基于 CSP 理论,核心理念是"不要通过共享内存来通信, 而应通过通信来共享内存"。本文将深入 Goroutine 的调度原理和 Channel 的实际应用。

Goroutine:轻量级并发单元

一个 Goroutine 的初始栈大小只有约 2KB,且可以动态增长和收缩。 在同一个进程中同时运行数万个 Goroutine 完全没有压力。

func main() {
    for i := 0; i < 10000; i++ {
        go worker(i)
    }
    time.Sleep(time.Second)
}

GPM 调度模型

  • G(Goroutine):用户态的轻量级协程
  • P(Processor):逻辑处理器,数量由 GOMAXPROCS 决定
  • M(Machine):操作系统线程,实际执行计算的单元

Channel:Goroutine 之间的通信桥梁

ch := make(chan int)       // 无缓冲
ch := make(chan int, 10)   // 有缓冲,容量 10

ch <- 42       // 发送
value := <-ch  // 接收

// 单向 Channel
func producer(out chan<- int) { ... }
func consumer(in <-chan int) { ... }

并发模式实战

Pipeline 模式

func gen(nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        for _, n := range nums { out <- n }
        close(out)
    }()
    return out
}

func square(in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        for n := range in { out <- n * n }
        close(out)
    }()
    return out
}

func main() {
    for result := range square(square(gen(1, 2, 3, 4, 5))) {
        fmt.Println(result)  // 1, 16, 81, 256, 625
    }
}

Fan-in 模式

func fanIn(channels ...<-chan int) <-chan int {
    var wg sync.WaitGroup
    out := make(chan int)
    for _, c := range channels {
        wg.Add(1)
        go func(c <-chan int) {
            defer wg.Done()
            for v := range c { out <- v }
        }(c)
    }
    go func() { wg.Wait(); close(out) }()
    return out
}

Context:优雅的取消与超时

func worker(ctx context.Context, id int) error {
    select {
    case <-time.After(time.Duration(id) * time.Second):
        return nil
    case <-ctx.Done():
        return ctx.Err()
    }
}

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()
    // ... 启动 workers
}

常见错误与最佳实践

  1. 不要通过共享内存来通信。优先使用 Channel 传递数据。
  2. 谁创建 Channel 谁关闭。向已关闭的 Channel 发送数据会 panic。
  3. 始终传递 Context。它是超时和取消控制的标准方式。
  4. 使用 sync.WaitGroup 等待 Goroutine 完成。

总结

Go 的并发模型优雅而强大。记住 Go 的并发哲学:通过通信来共享内存,而非通过共享内存来通信。

← 返回首页