You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何限制Go服务中异步任务的Goroutine并发数量?

限制异步任务Goroutine数量的方案

在Go场景下,最简洁高效的限流方式是用带缓冲的通道作为信号量,以此控制并发执行的Goroutine数量,避免无限制创建导致的资源耗尽问题。

核心实现思路

  1. 初始化一个带缓冲的通道,缓冲大小即为允许的最大异步任务并发数(比如设为10);
  2. 提交异步任务前,先向通道发送一个空结构体信号(空结构体不占用内存,性能最优);
  3. 异步任务执行完毕后,从通道接收信号释放名额,确保后续任务能获取资源。

修改后的完整代码示例

package main

import "sync"

type data struct {
    a int
    b bool
}

// 全局信号量通道,缓冲大小10代表最多同时执行10个异步任务
var semaphore = make(chan struct{}, 10)

func main() {
    // 模拟多请求并发场景
    var wg sync.WaitGroup
    for i := 0; i < 100; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            serverRequest()
        }()
    }
    wg.Wait()
}

func serverRequest() {
    d := syncWork()
    // 获取信号量,若通道已满则阻塞等待
    semaphore <- struct{}{}
    go func(d data) {
        // 确保任务完成后释放信号量,即使panic也不泄漏
        defer func() { <-semaphore }()
        asyncWork(d)
    }(d)
    // 直接返回响应,无需等待异步任务结束
}

func syncWork() data {
    return data{
        a: 10,
        b: false,
    }
}

func asyncWork(d data) {
    // 模拟网络调用或其他异步逻辑
    // time.Sleep(time.Second)
}

关键细节说明

  • 选用struct{}{}作为信号量载体,是因为它不占用内存空间,比int等类型更高效;
  • 必须在Goroutine内部用defer释放信号量,确保异常场景下也能正确回收资源,避免信号量泄漏;
  • 若使用HTTP框架(如Gin、Echo),可将信号量通道作为全局变量或注入服务实例,保证所有请求共享同一限流规则;
  • 如需动态调整并发数,可结合通道的cap()和len()做扩展,但固定初始化大小已能覆盖绝大多数业务场景。

内容的提问来源于stack exchange,提问作者Shikhar Tyagi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 22:35:04