Golang并行POST请求未生效:耗时远超预期问题排查
问题分析与解决方案
你的代码虽用goroutine发起请求,但实际未实现真正并行,总耗时远超预期,核心原因是Go标准库http.Client的默认连接池限制了单主机并发连接数,导致请求排队执行。
具体原因
Go的http.Transport默认配置中,MaxConnsPerHost(单主机最大并发连接数)默认值为2(部分版本可能调整,但早期版本均为此限制)。若所有请求发往同一目标主机,同一时间最多仅2个请求能执行,其余请求会阻塞等待连接释放,这就造成了你看到的请求分批返回、总耗时被拉长的现象——从日志能明显看出请求并非同时完成,而是间隔数秒到十数秒分批返回,完全符合连接池排队的特征。
解决步骤
1. 自定义HTTP客户端,调整连接池参数
修改types.PostJSON使用的HTTP客户端,增大单主机并发连接数:
// 自定义Transport,调整连接池参数 customTransport := &http.Transport{ MaxConnsPerHost: 100, // 设置与provider数量匹配的并发数 MaxIdleConns: 100, IdleConnTimeout: 30 * time.Second, } // 创建自定义客户端 client := &http.Client{ Transport: customTransport, Timeout: 10 * time.Second, // 设置合理请求超时 }
确保types.PostJSON内部使用该自定义client发起请求,而非默认的http.DefaultClient。
2. 改用带缓冲的Channel优化goroutine执行
当前代码使用无缓冲Channel,goroutine执行到ch <- response时会阻塞至主goroutine接收值。改为带缓冲的Channel可避免不必要的阻塞,让goroutine更快完成执行:
// 创建缓冲大小等于provider数量的Channel ch := make(chan models.SocketResource, len(providers))
3. 补充错误处理(可选但关键)
代码中忽略了PostJSON和json.Unmarshal的错误,可能隐藏请求失败问题,建议添加处理逻辑:
func process( provider models.Provider, query models.Query, db *sql.DB, ch chan<- models.SocketResource ) { body, raw, err := types.PostJSON(urlStr, string(jsonData), map[string]string{"Content-Type": "application/json"}, types.Proxy{}, jar) if err != nil { log.Printf("请求provider %s失败: %v", provider.Name, err) ch <- models.SocketResource{} // 发送空值避免主goroutine阻塞 return } response := models.RequestAnswers{} err = json.Unmarshal([]byte(body), &response) if err != nil { log.Printf("解析响应失败: %v", err) ch <- models.SocketResource{} return } ch <- response }
验证效果
修改后,所有请求将真正并行执行,总耗时会接近单个请求的最长响应时间(即你预期的5秒左右),而非所有请求耗时的累加。
内容的提问来源于stack exchange,提问作者vdkt
相关产品推荐
相关产品推荐

