
本文介绍使用 sync.waitgroup 并发调用两个返回不同类型结果的网络请求函数,并安全收集各自的结果与错误,避免阻塞、竞态和资源泄漏。
本文介绍使用 sync.waitgroup 并发调用两个返回不同类型结果的网络请求函数,并安全收集各自的结果与错误,避免阻塞、竞态和资源泄漏。
在 Go 中实现两个独立网络请求的并发执行,关键在于解耦执行与结果收集:既要并行发起请求以节省总耗时,又要分别捕获各自返回的不同类型结果和错误。直接顺序调用(resultA, err := request1(); resultB, err := request2())会串行等待,失去并发优势;而若强行共用单一 channel,则因 resultTypeA 与 resultTypeB 类型不兼容,违背 Go 的类型安全原则。
推荐采用 sync.WaitGroup 配合闭包捕获变量的经典模式——轻量、清晰、无额外依赖。以下是完整、健壮的实现:
import "sync"
func fetchBoth() (resultTypeA, resultTypeB, error) {
var wg sync.WaitGroup
wg.Add(2)
var (
resultA resultTypeA
errA error
resultB resultTypeB
errB error
)
// 并发执行 request1
go func() {
defer wg.Done()
resultA, errA = request1()
}()
// 并发执行 request2
go func() {
defer wg.Done()
resultB, errB = request2()
}()
wg.Wait() // 等待两个 goroutine 全部完成
// 统一检查错误(可根据业务逻辑调整策略:如任一失败即返回,或分别处理)
if errA != nil {
return resultA, resultB, errA
}
if errB != nil {
return resultA, resultB, errB
}
return resultA, resultB, nil
}✅ 关键要点说明:
- 使用 defer wg.Done() 替代手动 wg.Done(),确保即使函数 panic 也能正确计数;
- 所有结果与错误变量均在主 goroutine 中声明(栈上分配),避免闭包引用导致的意外共享;
- wg.Wait() 是同步阻塞点,但仅等待 goroutine 结束,不参与 I/O,开销极低;
- 错误处理策略灵活:示例采用“全成功才返回结果”,你也可改为收集所有错误(如使用 []error)或执行降级逻辑。
⚠️ 注意事项:
- 切勿在 goroutine 中直接 return —— 它只退出该 goroutine,不影响外层函数;
- 若请求函数内部未设置超时(如 http.Client.Timeout),建议为每个 requestX() 添加上下文控制(context.WithTimeout),防止单个请求无限挂起拖垮整个并发流程;
- 高频调用场景下,可考虑复用 sync.Pool 缓存 WaitGroup 实例(但通常无需,因其本身极轻量)。
此模式简洁、可读性强,是 Go 标准库推荐的并发协调方式之一,适用于任意数量(不限于两个)的异构异步任务协同。

















