提示:本网站现在为维护调试状态

Go 語言併發:goroutine + channel + sync.WaitGroup

Choyeon
Choyeon
2026年9月8日 1 分鐘閱讀 586 閱讀
559 字 1,909 字元 更新於 2026年11月8日
Go 語言併發:goroutine + channel + sync.WaitGroup
目錄

Go 语言并发:goroutine + channel + sync.WaitGroup

Go 最引以为豪的特性就是原生并发模型:"不要通过共享内存通信,而要通过通信共享内存"。goroutine + channel 的 CSP 模式让并发代码可读性和安全性大幅提升。

goroutine 与工作池模式

一个 goroutine 初始栈仅 2KB,可以轻松启动十万级别。通过带缓冲 channel 实现固定大小 worker pool,避免无限创建导致调度压力,用 sync.WaitGroup 等待所有 worker 退出。

package main

import (
    "context"
    "fmt"
    "log"
    "sync"
    "time"
)

type Job struct{ ID int; URL string }
type Result struct{ JobID int; Latency time.Duration; Status int; Err error }

func worker(ctx context.Context, id int, jobs <-chan Job, results chan<- Result, wg *sync.WaitGroup) {
    defer wg.Done()
    log.Printf("[worker %d] started", id)
    for {
        select {
        case <-ctx.Done():
            log.Printf("[worker %d] cancelled: %v", id, ctx.Err())
            return
        case job, ok := <-jobs:
            if !ok { return }
            t0 := time.Now()
            select {
            case <-ctx.Done():
                results <- Result{JobID: job.ID, Err: ctx.Err()}
                return
            case <-time.After(500 * time.Millisecond):
                results <- Result{JobID: job.ID, Latency: time.Since(t0), Status: 200}
            }
        }
    }
}

func main() {
    const (
        workerCount = 4
        jobCount    = 20
    )
    ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
    defer cancel()
    jobs := make(chan Job, workerCount*2)
    results := make(chan Result, workerCount*2)
    var wg sync.WaitGroup
    for i := 1; i <= workerCount; i++ {
        wg.Add(1)
        go worker(ctx, i, jobs, results, &wg)
    }
    go func() {
        for i := 1; i <= jobCount; i++ {
            jobs <- Job{ID: i, URL: fmt.Sprintf("https://api.example.com/item/%d", i)}
        }
        close(jobs)
    }()
    go func() { wg.Wait(); close(results) }()
    total := 0
    for r := range results {
        total++
        if r.Err != nil { fmt.Printf("[job %02d] ERROR %v\n", r.JobID, r.Err) }
        fmt.Printf("[job %02d] status=%d latency=%-8s total=%d\n", r.JobID, r.Status, r.Latency, total)
    }
    fmt.Printf("Done: %d/%d jobs\n", total, jobCount)
}

Context 取消与陷阱

context.WithTimeout/WithCancel 同时关闭所有嵌套协程,是防止泄漏的关键。常见陷阱:for-range 读已关闭 channel 自动退出、select 加 default 变成忙循环、无缓冲 channel 发送端阻塞造成 goroutine 悬挂。

特性 Go goroutine+channel Java Thread+Queue Rust async+tokio
最小开销 ~2KB栈 ~1MB栈 结构体级
启动10万耗时 <100ms 数秒/OOM ~200ms
同步原语 channel/mutex/Cond BlockingQueue/锁 tokio::sync::*
取消机制 Context统一 Future.cancel/中断 Drop/select!
常见陷阱 goroutine泄漏/阻塞 虚假唤醒/死锁 Pin! 生命周期

最佳实践

发送端 close channel,不要接收端关。优先使用有界缓冲 channel,避免无界队列导致内存暴涨。用 defer 覆盖所有关闭路径,防止异常下 goroutine 泄漏。

X微博Telegram

本文作者

投票

你最希望 Rosetta 优先加入哪项功能?

社区投票(演示数据,可后台删除)

留言 (6)

0 / 3000
摸鱼达人小王
摸鱼达人小王2026年9月21日

好文!但是我觉得第三部分那个消息队列选型对比表有点偏向 Kafka 了,RocketMQ 在事务消息这块其实优势挺明显的。

机器学习萌新
机器学习萌新2026年9月21日

受益匪浅,感谢大佬分享!

运维老司机
运维老司机ops-notes.cn2026年9月21日

哈哈,楼主的踩坑经历和我一模一样!我当时就是没注意到这个配置,排查了整整两天,看到这篇文章泪目了。

数据库小管家
数据库小管家dbtips.pro2026年9月20日

楼主,我按照你的步骤操作后启动报错:Error creating bean with name 'dataSource',版本是 Spring Boot 3.2,请问有遇到过吗?

架构师小李
架构师小李archinsights.blog2026年9月20日

代码示例里那个 SQL 查询是不是应该加个 LIMIT?不然数据量大的时候全表扫描会很慢哦。

全栈打工人
全栈打工人2026年9月20日

写得太好了,终于搞懂了分布式事务的几种方案区别,收藏了!

相關文章

Redis 緩存設計模式

Redis 緩存設計模式

系統講解三種核心緩存模式:Cache-Aside(旁路緩存)一致性保障、Write-Through(寫穿透)原子性保證、Write-Behind(寫回)高吞吐異步寫入,以及緩存擊穿/穿透/雪崩解決方案。

1 分鐘閱讀
Node.js 性能診斷:clinic.js + flamegraph

Node.js 性能診斷:clinic.js + flamegraph

系統學習 Node.js 性能定位工具鏈:clinic.js 一鍵生成分析報告,解讀火焰圖熱點函數、阻塞事件循環的同步代碼、內存洩漏對象棧,精準定位 CPU/內存瓶頸。

1 分鐘閱讀
PostgreSQL 查詢優化技巧

PostgreSQL 查詢優化技巧

深入掌握 PostgreSQL 查詢優化的核心方法:從 EXPLAIN ANALYZE 執行計劃解讀,到索引類型選擇(B-tree/GIN/BRIN)、統計資訊更新、連接策略調整、分區表設計,全方位提升數據庫查詢性能。

1 分鐘閱讀
Rust 所有權與借用機制:徹底理解生命週期

Rust 所有權與借用機制:徹底理解生命週期

系統攻克 Rust 最獨特概念:所有權規則、可變/不可變借用約束、引用生命週期標註。通過編譯錯誤示例 + 修復方案,徹底掌握借用檢查器思維方式,寫出安全零抽象開銷的系統代碼。

1 分鐘閱讀
Linux 性能調優:perf_events + bpftrace + BCC

Linux 性能調優:perf_events + bpftrace + BCC

從 CPU、內存、IO、網絡四個維度,使用 perf_events 採樣堆棧、bpftrace 一行腳本追蹤內核點、BCC 工具集 biolatency/offcputime,快速定位生產服務器性能瓶頸,附真實排查思路。

1 分鐘閱讀
Python 併發:asyncio vs ThreadPool vs ProcessPool

Python 併發:asyncio vs ThreadPool vs ProcessPool

深度對比 Python 三大併發模型:GIL 限制下的線程池(IO 密集)、進程池(繞 GIL 適合 CPU 密集)、asyncio 協程(超高併發 IO)。從原理/性能/複雜度四維度給出選型決策樹。

1 分鐘閱讀