Go语言中处理网络请求并发常用方法包括:1. 使用Goroutine+WaitGroup控制并发,确保所有请求完成;2. 通过Channel收集结果并限制并发数,避免资源耗尽;3. 利用errgroup简化错误处理与任务取消;4. 结合context实现超时控制与请求取消。根据不同场景选择合适方式,可高效管理并发网络请求。

在Go语言中处理网络请求并发非常常见,尤其是在构建API服务、微服务调用或数据抓取工具时。Golang凭借其轻量级的goroutine和强大的标准库,天生适合高并发场景。下面介绍几种常用的并发处理方法,帮助你高效、安全地管理多个网络请求。
使用Goroutine + WaitGroup控制并发
这是最基础也是最常用的并发模式。通过sync.WaitGroup等待所有goroutine完成,避免主程序提前退出。
示例:并发发起多个HTTP请求并等待结果
package mainimport ( "fmt" "net/http" "sync" )
func fetch(url string, wg *sync.WaitGroup) { defer wg.Done() resp, err := http.Get(url) if err != nil { fmt.Printf("Error fetching %s: %v\n", url, err) return } defer resp.Body.Close() fmt.Printf("Fetched %s with status %s\n", url, resp.Status) }
func main() { urls := []string{ "https://www.php.cn/link/4d2fe2e8601f7a8018594d98f28706f2", "https://www.php.cn/link/5f69e19efaba426d62faeab93c308f5c", "https://www.php.cn/link/98a733901e53052474f2320d0a3a9473", }
var wg sync.WaitGroup for _, url := range urls { wg.Add(1) go fetch(url, &wg) } wg.Wait()}
立即学习“go语言免费学习笔记(深入)”;
使用Channel收集结果与控制并发数
当需要获取每个请求的结果(如响应体或状态)时,可以通过channel将结果传回主协程。同时可用带缓冲的channel限制最大并发数,防止资源耗尽。
示例:限制5个并发请求,使用channel接收结果
type result struct {
url string
status string
err error
}
func fetchWithResult(url string, ch chan<- result) {
resp, err := http.Get(url)
if err != nil {
ch <- result{url: url, err: err}
return
}
defer resp.Body.Close()
ch <- result{url: url, status: resp.Status}
}
func main() {
urls := [...]string{ / 同上 / }
ch := make(chan result, len(urls))
sem := make(chan struct{}, 5) // 并发信号量,最多5个并发
for _, url := range urls {
go func(u string) {
sem <- struct{}{} // 获取令牌
fetchWithResult(u, ch)
<-sem // 释放令牌
}(url)
}
for range urls {
r := <-ch
if r.err != nil {
fmt.Printf("Failed: %s - %v\n", r.url, r.err)
} else {
fmt.Printf("Success: %s - %s\n", r.url, r.status)
}
}}
立即学习“go语言免费学习笔记(深入)”;
使用errgroup简化错误处理
golang.org/x/sync/errgroup提供了一种更优雅的方式处理并发任务中的错误。任何一次请求出错,整个组可以快速取消,并返回首个错误。
示例:使用errgroup并发请求,任一失败则中断
package mainimport ( "context" "fmt" "net/http" "golang.org/x/sync/errgroup" )
func main() { urls := [...]string{ / 同上 / } ctx := context.Background() g, ctx := errgroup.WithContext(ctx)
for _, url := range urls { url := url // 避免循环变量捕获 g.Go(func() error { req, _ := http.NewRequestWithContext(ctx, "GET", url, nil) resp, err := http.DefaultClient.Do(req) if err != nil { return err } defer resp.Body.Close() fmt.Printf("Got %s: %s\n", url, resp.Status) return nil }) } if err := g.Wait(); err != nil { fmt.Printf("Request failed: %v\n", err) }}
立即学习“go语言免费学习笔记(深入)”;
超时控制与上下文传递
网络请求必须设置超时,避免长时间阻塞。使用context.WithTimeout可统一控制所有请求的最长执行时间。
建议做法:
- 为每个请求绑定context,设置合理超时(如5秒)
- 在errgroup或自定义goroutine中传递context
- 客户端也可设置默认超时:http.Client{Timeout: 5 * time.Second}
基本上就这些常用方式。根据场景选择:简单并发用WaitGroup,需结果用channel+缓冲池,强调错误处理和取消用errgroup。配合context做超时和取消,能写出稳定高效的并发网络代码。










