0

0

Go语言并发设计模式有哪些_Golang并发模式总结

P粉602998670

P粉602998670

发布时间:2026-01-15 12:46:46

|

198人浏览过

|

来源于php中文网

原创

Go语言最常用、最值得优先掌握的五个并发设计模式是Fan-out/Fan-in、Worker Pool、Pipeline、Producer-Consumer、Batch Processing,它们均符合Go“通过通信共享内存”的哲学,能用channel自然表达、配合WaitGroup或context控制生命周期、避免裸用mutex。

go语言并发设计模式有哪些_golang并发模式总结

Go语言最常用、最值得优先掌握的并发设计模式就五个:Fan-out / Fan-in、Worker Pool、Pipeline、Producer-Consumer、Batch Processing。它们不是理论概念,而是你写高并发服务时每天都会用到的实操结构。

为什么选这五个?——不是所有“模式”都值得投入时间

Go 的并发哲学是“通过通信共享内存”,所以真正落地有效的模式,必须满足三个条件:能用 channel 自然表达、能配合 sync.WaitGroupcontext.Context 控制生命周期、避免裸用 mutex 做协调。这五个模式全部符合,其余诸如 “Single-Flight” 或 “Circuit Breaker” 属于业务层抽象,不属于 Go 并发原语范畴。

Fan-out / Fan-in:处理“多任务分发 + 结果聚合”的标准解法

当你需要把一批任务(比如 100 个 URL 抓取)并发分给多个 goroutine 处理,并把结果统一收回来,Fan-out / Fan-in 就是最直接的选择。它比手写 WaitGroup + slice 更安全,也比全塞进一个 channel 更可控。

  • 扇出(Fan-out):用一个 for 循环向多个 worker 的输入 channel 发送任务,或直接启动多个 goroutine 读同一个输入 channel
  • 扇入(Fan-in):用一个 merge 函数把多个输出 channel 合并成一个 —— 切忌用 for range 直接遍历多个 channel,必须用 select 轮询或 goroutine + channel 中转
  • 常见错误:忘记 close 输入 channel,导致 worker 卡在 range;或没等所有 worker 退出就关闭输出 channel,造成 panic
func merge(chs ...<-chan int) <-chan int {
    out := make(chan int)
    var wg sync.WaitGroup
    wg.Add(len(chs))
    for _, ch := range chs {
        go func(c <-chan int) {
            defer wg.Done()
            for n := range c {
                out <- n
            }
        }(ch)
    }
    go func() {
        wg.Wait()
        close(out)
    }()
    return out
}

Worker Pool:控制并发数、防雪崩的刚需模式

如果你的程序要处理大量请求(如 HTTP 接口批量调用外部 API),不加限制地起 goroutine,很容易打爆下游或耗尽内存。Worker Pool 通过固定数量的长期 goroutine 消费任务队列,实现资源硬限流。

立即学习go语言免费学习笔记(深入)”;

魔法映像企业网站管理系统
魔法映像企业网站管理系统

技术上面应用了三层结构,AJAX框架,URL重写等基础的开发。并用了动软的代码生成器及数据访问类,加进了一些自己用到的小功能,算是整理了一些自己的操作类。系统设计上面说不出用什么模式,大体设计是后台分两级分类,设置好一级之后,再设置二级并选择栏目类型,如内容,列表,上传文件,新窗口等。这样就可以生成无限多个二级分类,也就是网站栏目。对于扩展性来说,如果有新的需求可以直接加一个栏目类型并新加功能操作

下载
  • 核心结构:一个带缓冲的 jobs chan int + N 个常驻 worker goroutine + 一个 sync.WaitGroup 管理生命周期
  • 关键细节:必须在发送完所有任务后 close(jobs),否则 worker 会永远阻塞在 range jobs;如果任务有返回值,建议用单独的 results chan,别和 jobs 混用
  • 容易踩坑:用 make(chan int, 0)(无缓冲)当任务队列 —— 这会导致主 goroutine 在发第一个任务时就阻塞,除非同时有 worker 在读;正确做法是带缓冲,比如 make(chan int, 100)

Pipeline 与 Producer-Consumer:什么时候该用哪个?

Pipeline 是一种数据流分阶段处理的建模方式(比如:解析 → 过滤 → 转换 → 存储),每个阶段是一个独立 goroutine,靠 channel 串起来;Producer-Consumer 更侧重角色分离(生产者只管发,消费者只管收),不要求阶段化。

  • 选 Pipeline 当你需要清晰划分处理逻辑层级,且每阶段可能复用或替换(例如日志处理流水线)
  • 选 Producer-Consumer 当你明确区分 IO 与 CPU 密集型任务(如:文件读取器 producer + JSON 解析器 consumer)
  • 共同雷区:中间 channel 忘记 close,导致下游 goroutine 永远等不到 EOF;或某个阶段 panic 后未通知其他阶段退出,造成 goroutine 泄漏
  • 实用技巧:用 context.WithCancel 包裹整个 pipeline,一处 cancel 全链路退出

Batch Processing:简单但最容易被低估的模式

它看起来最“土”,却是处理大批量静态数据(如 CSV 导入、数据库迁移)时最稳的方式。比起泛滥的 “全量启 goroutine”,它用可控批大小(如每批 100 条)平衡吞吐与内存压力。

  • 不要硬编码 batchSize := 100 —— 应根据单条任务内存占用和 GC 压力动态估算,比如处理大 struct 时批大小应 ≤ 10
  • 每个 batch 启一个 goroutine 是 OK 的,但记得用 sync.WaitGroup 等待全部完成;别用 for i := range batches { go process(batches[i]) } —— 这里 i 是循环变量,闭包捕获的是同一地址,大概率全处理错批次
  • 若某批失败,是否重试?是否跳过?这些策略不在模式本身,但必须在 process 函数里显式处理,别指望上层兜底

真正难的从来不是“知道有哪些模式”,而是面对一个新需求时,能快速判断:该用 Fan-in 收集结果,还是用 Worker Pool 控制并发,抑或干脆 Batch Processing 更稳妥。这种判断力,来自对每个模式边界和代价的切身理解 —— 比如你知道 merge 函数里那个 close(out) 必须放在 wg.Wait() 之后,否则下游 range 会 panic;你也知道 jobs channel 不 close,worker 就永远不会退出。这些细节,才是并发不出错的关键。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

411

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

532

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

309

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

74

2025.09.10

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

315

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

537

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

52

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

197

2025.08.29

Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

0

2026.01.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8.3万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 3.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号