← 返回资讯
陈默
AI 行业分析师
已审核

Go 并发模式:从 Goroutine 到 Channel 的实战指南

title: "Go 并发模式:从 Goroutine 到 Channel 的实战指南"

Go 并发模式:从 Goroutine 到 Channel 的实战指南

title: "Go 并发模式:从 Goroutine 到 Channel 的实战指南"

date: "2026-07-10"

tags: ["Go", "并发", "Goroutine", "Channel"]


Go 并发模式:从 Goroutine 到 Channel 的实战指南

Go 的并发模型是其最强大的特性之一。理解 goroutine 和 channel 的正确用法,是写出高性能 Go 程序的基础。

Goroutine 基础

GO
package main

import (
    "fmt"
    "time"
)

func processTask(id int) {
    fmt.Printf("任务 %d 开始\n", id)
    time.Sleep(time.Second)
    fmt.Printf("任务 %d 完成\n", id)
}

func main() {
    // 启动 5 个 goroutine
    for i := 0; i < 5; i++ {
        go processTask(i)
    }
    
    // 等待所有 goroutine 完成
    time.Sleep(2 * time.Second)
}

WaitGroup

GO
package main

import (
    "fmt"
    "sync"
    "time"
)

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()
    
    fmt.Printf("Worker %d 开始\n", id)
    time.Sleep(time.Second)
    fmt.Printf("Worker %d 完成\n", id)
}

func main() {
    var wg sync.WaitGroup
    
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go worker(i, &wg)
    }
    
    wg.Wait()
    fmt.Println("所有 worker 完成")
}

Channel 基础

GO
package main

import "fmt"

func producer(ch chan<- int) {
    for i := 0; i < 5; i++ {
        ch <- i
    }
    close(ch)
}

func consumer(ch <-chan int) {
    for val := range ch {
        fmt.Printf("收到: %d\n", val)
    }
}

func main() {
    ch := make(chan int)
    
    go producer(ch)
    consumer(ch)
}

工作池模式

GO
package main

import (
    "fmt"
    "sync"
    "time"
)

type Job struct {
    ID      int
    Payload string
}

type Result struct {
    JobID  int
    Output string
}

func worker(id int, jobs <-chan Job, results chan<- Result, wg *sync.WaitGroup) {
    defer wg.Done()
    
    for job := range jobs {
        // 处理任务
        time.Sleep(100 * time.Millisecond)
        results <- Result{
            JobID:  job.ID,
            Output: fmt.Sprintf("Worker %d 处理了 %s", id, job.Payload),
        }
    }
}

func main() {
    const numWorkers = 5
    const numJobs = 20
    
    jobs := make(chan Job, numJobs)
    results := make(chan Result, numJobs)
    
    var wg sync.WaitGroup
    
    // 启动 worker
    for i := 0; i < numWorkers; i++ {
        wg.Add(1)
        go worker(i, jobs, results, &wg)
    }
    
    // 发送任务
    for i := 0; i < numJobs; i++ {
        jobs <- Job{ID: i, Payload: fmt.Sprintf("task-%d", i)}
    }
    close(jobs)
    
    // 等待所有 worker 完成
    wg.Wait()
    close(results)
    
    // 收集结果
    for result := range results {
        fmt.Println(result.Output)
    }
}

Fan-Out / Fan-In

GO
package main

import (
    "fmt"
    "sync"
)

func fanOut(input <-chan int, numWorkers int) []<-chan int {
    channels := make([]<-chan int, numWorkers)
    
    for i := 0; i < numWorkers; i++ {
        channels[i] = process(input)
    }
    
    return channels
}

func process(input <-chan int) <-chan int {
    output := make(chan int)
    
    go func() {
        defer close(output)
        for val := range input {
            output <- val * 2
        }
    }()
    
    return output
}

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

func main() {
    input := make(chan int)
    
    go func() {
        for i := 0; i < 10; i++ {
            input <- i
        }
        close(input)
    }()
    
    channels := fanOut(input, 3)
    merged := fanIn(channels...)
    
    for val := range merged {
        fmt.Println(val)
    }
}

Context 控制

GO
package main

import (
    "context"
    "fmt"
    "time"
)

func longRunningTask(ctx context.Context) error {
    select {
    case <-time.After(5 * time.Second):
        fmt.Println("任务完成")
        return nil
    case <-ctx.Done():
        fmt.Println("任务取消:", ctx.Err())
        return ctx.Err()
    }
}

func main() {
    // 超时控制
    ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
    defer cancel()
    
    err := longRunningTask(ctx)
    if err != nil {
        fmt.Println("错误:", err)
    }
}

并发安全

GO
package main

import (
    "fmt"
    "sync"
)

type Counter struct {
    mu    sync.RWMutex
    value int
}

func (c *Counter) Increment() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.value++
}

func (c *Counter) Value() int {
    c.mu.RLock()
    defer c.mu.RUnlock()
    return c.value
}

func main() {
    counter := &Counter{}
    var wg sync.WaitGroup
    
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            counter.Increment()
        }()
    }
    
    wg.Wait()
    fmt.Println("最终值:", counter.Value())  // 1000
}

Pipeline 模式

GO
package main

import "fmt"

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

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

func filter(in <-chan int, threshold int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for n := range in {
            if n > threshold {
                out <- n
            }
        }
    }()
    return out
}

func main() {
    // 构建 pipeline: generator -> square -> filter
    nums := generator(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    squares := square(nums)
    filtered := filter(squares, 20)
    
    for n := range filtered {
        fmt.Println(n)  // 25, 36, 49, 64, 81, 100
    }
}

Go 的并发哲学是"不要通过共享内存来通信,而要通过通信来共享内存"。正确使用 channel 和 goroutine,能构建出既高效又安全的并发程序。

272
13604 阅读
2 评论
分享
链接已复制
编辑说明

本文由 MakeSense 编辑团队撰写并审核。文中引用的数据和观点均经过交叉验证,如有疏漏欢迎在评论区指正。最后更新:2026年07月11日 08:59

陈默

AI 行业分析师

前某大厂 AI 实验室研究员,关注大模型技术演进和商业化落地。写过 200+ 篇行业分析,擅长从产品视角拆解技术趋势。

读者评论 2

技术小白 1周前
作为非技术人员也看懂了,感谢作者的通俗讲解。
回复 点赞 (3)
Dev小王 2周前
终于有人把这个说清楚了,收藏了。
回复 点赞 (8)