Golang 如何限制并发数
一款功能相当强大的录音及音频编辑软件,不仅可以编辑音频,而且还可以录音,功能丰富,操作简单,使用方便,实用性强,并且占用电脑内存小,运行速度快,不卡顿电脑,使电脑系统保持良好的运行状态。支持许多格式的音频文件,包括WAV、OGG、VOC、IFF、AIFF、
Golang 如何限制并发数 用 sync.Semaphore(Go 1.21+)最稳妥 从Go 1.21开始,标准库自带的 sync.Semaphore 就成了生产环境的首选方案。它可不是一个简单的计数器,而是一个功能完备的信号量实现,支持权重、上下文取消,并且是panic安全的。 不过,用起来有
Golang 如何限制并发数

用 sync.Semaphore(Go 1.21+)最稳妥
从Go 1.21开始,标准库自带的 sync.Semaphore 就成了生产环境的首选方案。它可不是一个简单的计数器,而是一个功能完备的信号量实现,支持权重、上下文取消,并且是panic安全的。
不过,用起来有几个细节必须注意,否则很容易踩坑:
- 初始化必须传
int64:比如你想限制8个并发,得写成semaphore.NewWeighted(8)。如果传一个普通的8(int类型),编译器会直接报错。 sem.Acquire(ctx, 1)必须检查返回的 error —— 如果上下文(ctx)已经取消或超时,这个方法会立刻返回context.Canceled或context.DeadlineExceeded。这时候,可千万别再执行业务逻辑了。defer sem.Release(1)要写在 goroutine 的最外层:这个习惯能保证,即使你的doWork()函数 panic 了,defer 语句依然会执行,令牌不会泄漏。- 别把
ctx只用在Acquire上:如果你的业务逻辑本身需要发起 HTTP 请求,记得把同一个ctx也传给http.Client.Do()。否则,可能会出现信号量等到了,但请求却卡死在 TCP 握手阶段的尴尬情况。
用 chan struct{} 模拟信号量(兼容所有 Go 版本)
对于简单的场景,用通道(channel)模拟信号量是个轻量且零依赖的选择,所有 Go 版本都兼容。但这个方法有个致命弱点:极易翻车——只要漏释放一次令牌,后续所有任务就会永久阻塞。
想用对,得盯紧下面几点:
- 声明必须带缓冲:正确写法是
sem := make(chan struct{}, 5)。如果写成无缓冲的make(chan struct{}),那就完全失去了限流的意义。 - 获取和释放必须严格配对:
sem <- struct{}{}是占位,<-sem是归还。另外,别用len(sem)来判断是否能进入,它返回的是已占用的数量,可用数应该是cap(sem) - len(sem)。 - 安全写法是
defer func() { <-sem }():但要注意,闭包捕获的变量需要显式传入。比如在循环里启动 goroutine,应该写成go func(s chan struct{}) { s <- struct{}{}; defer func() { <-s }(); ... }(sem),否则闭包捕获的可能是循环的最终值,导致所有任务挤进同一个“槽位”。 - 别在
select里只写case <-sem:就开干:万一任务在注册 defer 之前就 panic 了,令牌可就找不回来了。
HTTP 请求并发限制,关键位置在哪
限制 HTTP 请求并发,关键在于把限流逻辑放在真正发起网络调用的那一刻之前,而不是在启动 goroutine 时,更不是在 for 循环外面。很多人把信号量放错了位置,结果下游服务的 QPS 照样被打满。
- 正确位置:在
http.NewRequest()之后,client.Do()之前。这样,即使请求失败、超时、甚至 panic,defer 也能保证令牌被安全归还。 - 错误示范:
for range urls { go func() { sem <- struct{}{}; ... }() }—— 这里的sem <-虽然在 goroutine 内部,但如果 goroutine 启动过快,实际并发连接数依然不可控。更糟的是把信号量操作放在 for 循环里、goroutine 外部,那只是限制了 goroutine 的启动速度,对网络并发毫无约束。 http.Transport的MaxConnsPerHost不等于并发请求数:这个参数控制的是 TCP 连接池的复用上限,它和信号量是协作关系,而非替代关系。通常建议将信号量设为你的业务目标并发数(例如10),而将MaxConnsPerHost设为一个略大的值(例如15),以允许合理的连接复用。
什么时候该换 worker pool,而不是只靠信号量
信号量只回答了“最多几个任务同时跑”的问题,但它不关心“谁来跑”、“跑几次”以及“任务积压了怎么办”。一旦遇到以下几种情况,就该考虑升级到更复杂的 worker pool 模式了:
- 需要拒绝新任务,而不是无限排队等待:信号量会阻塞等待,而像
ants这样的 worker pool 库,可以通过配置ants.WithNonblocking(true)来直接丢弃无法立即处理的任务。 - 需要统计实时指标:比如当前正在运行的任务数、排队中的任务数量、任务平均耗时等。裸信号量无法提供这些观测维度。
- 任务执行时间差异极大,存在长期挂起的风险:比如调用某个不稳定的第三方接口。worker pool 可以内置超时和熔断机制,而信号量只能被动等待任务自己结束。
- 你已经在使用
ants或类似库:这类库的NewPool(n)本质上封装了信号量、goroutine 预热以及 panic 捕获,比自己手写更稳健。但要注意,如果 worker 数量(n)远小于任务总量,且没有设置合理的任务队列缓冲,可能会导致大量任务被静默丢弃。
Postman是一套面向API全生命周期的开发与测试平台,可在Mac上发送和调试多种协议请求,管理集合、环境及认证信息,并完成脚本测试、模拟服务、监控、文档发布和团队协作。它适合开发、测试及运维人员使用,提供个人免费方案。
Docker Desktop 是 Docker 官方为 Mac 提供的容器开发环境,集成 Docker Engine、命令行工具、Compose、Build、Kubernetes 与图形化管理界面。
Android Studio 是 Google 面向安卓应用开发提供的官方集成开发环境,基于 IntelliJ IDEA 构建。它整合智能代码编辑、Gradle 构建、界面预览、设备模拟、性能分析、调试测试及 APK 分析等工具。
PixPix 是面向品牌、卖家和内容团队的在线 AI 图片视频创作平台,提供图视频 Agent、无限画布、图片生成、视频生成、自然语言编辑及商品套图、产品精修和带货视频等电商工具。
Postman 是面向 API 全生命周期的开发与协作平台。Windows 桌面版可用于构建和发送 HTTP、GraphQL、gRPC、WebSocket、MQTT 等请求,并提供环境变量、集合、脚本测试、模拟服务、监控、文档及团队工作区等
Docker Desktop 为 Windows 开发者提供集成式容器环境,内置 Docker Engine、命令行工具、Compose、Build 与 Kubernetes 等组件,可在本机完成镜像构建、容器运行、日志查看和资源管理。













