go的http.get()默认使用无超时的http.defaultclient,且transport的maxidleconnsperhost默认仅2,未设timeout、dialcontext等超时参数,导致dns/tls/读响应头等阶段卡死,goroutine堆积。

为什么直接用 go http.Get() 容易卡死或超时?
不是 Goroutine 本身有问题,而是没控制并发数 + 缺少超时和错误隔离。常见现象是:发起几十个 go http.Get() 后,部分请求永远不返回,或整个程序被 DNS 解析阻塞、TCP 连接耗尽。根本原因是 Go 的默认 http.DefaultClient 复用底层 net/http.Transport,而它的 MaxIdleConns 和 MaxIdleConnsPerHost 默认值极低(都是 100),且没有设置 Timeout 或 IdleConnTimeout。
实操建议:
- 必须自定义
http.Client,显式设置Timeout(如 10 秒)、Transport.IdleConnTimeout(建议 30 秒) - 限制并发数(例如用带缓冲的 channel 或
semaphore控制 goroutine 数量),避免打爆目标服务或本地文件描述符 - 每个请求都应单独处理 error,不能因为一个失败就 panic 或忽略后续结果
如何安全地并发抓取并收集响应结果?
用无缓冲 channel 传 struct 最直观,但要注意:如果接收端不及时读,发送端会阻塞 —— 这反而让 goroutine 堆积。更稳妥的是用带缓冲 channel(容量 ≥ 并发数),或改用 sync.WaitGroup + 闭包捕获变量。
示例关键逻辑:
type Result struct {
URL string
Status int
Body []byte
Err error
}
<p>results := make(chan Result, 20) // 缓冲大小匹配并发上限
var wg sync.WaitGroup</p><p>for <em>, url := range urls {
wg.Add(1)
go func(u string) {
defer wg.Done()
resp, err := client.Get(u)
if err != nil {
results := io.ReadAll(resp.Body)
results <p>go func() {
wg.Wait()
close(results)
}()</p>
<p>for r := range results {
// 处理每个结果
}</p></em></p>
context.WithTimeout 必须在每个请求里用,不能只在外层套一次
外层一个 context.WithTimeout 然后传给所有 goroutine,看似省事,实际会导致:只要第一个请求超时,其余所有请求立刻被 cancel —— 完全失去并发意义。每个请求必须有自己独立的 context。
正确写法:
- 在 goroutine 内部创建
ctx, cancel := context.WithTimeout(context.Background(), 8*time.Second) - 调用
client.Do(req.WithContext(ctx)),而不是client.Get()(因为Get不接受 context) - 务必调用
cancel(),否则可能泄漏 timer
漏掉 cancel() 是高频 bug,尤其在 error 分支里忘记调用,会导致大量 goroutine 持有 timer 直到超时,内存缓慢上涨。
为什么用 fasthttp 替代 net/http 能明显提升吞吐?
net/http 每次请求都分配新 http.Request 和 http.Response,GC 压力大;而 fasthttp 复用 RequestCtx 和底层 buffer,实测在高并发短连接场景下 QPS 可翻倍以上,内存分配减少 70%+。
但注意兼容性断点:
-
fasthttp不遵循 HTTP/1.1 标准细节(比如某些 header 自动小写、不支持 HTTP/2) - 它不提供
http.Handler接口,无法直接跑在标准 Go HTTP server 上 - 重定向、cookie、proxy 等需手动处理,
fasthttp.LoopbackResolver才能支持localhost解析
如果你只是做爬虫类批量请求,且目标站不依赖复杂 header 或重定向链,fasthttp 是更轻量的选择;但若需调试中间件、复用现有 http.RoundTripper 配置,还是老实用 net/http 加强管控。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











