ioutil.ReadAll导致goroutine泄漏

Nim*_*adi 1 go goroutine

为什么我在终止之前有多个goroutine,即使我关闭了resp.body,而我只使用了阻止调用?如果我不消耗resp.Body它只用一个goroutine终止.

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "runtime"
    "time"
)

func fetch() {
    client := http.Client{Timeout: time.Second * 10}
    url := "http://example.com"
    req, err := http.NewRequest("POST", url, nil)
    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    _, err = ioutil.ReadAll(resp.Body)
    if err != nil {
        panic(err)
    }
}

func main() {
    fmt.Println("#Goroutines:", runtime.NumGoroutine())
    fetch()
    // runtime.GC()
    time.Sleep(time.Second * 5)
    fmt.Println("#Goroutines:", runtime.NumGoroutine())
}
Run Code Online (Sandbox Code Playgroud)

输出:

#Goroutines: 1
#Goroutines: 3
Run Code Online (Sandbox Code Playgroud)

Pet*_*ter 7

默认的http传输维护连接池.

DefaultTransport是Transport的默认实现,由DefaultClient使用.它根据需要建立网络连接,并将其缓存以供后续调用重用.

每个连接由至少一个goroutine管理.这不是泄漏,你只是不耐烦.如果你等待足够长的时间,你会看到连接最终关闭,goroutine消失了.默认空闲超时为90秒.

如果要以asap方式关闭连接,请将http.Request.Closehttp.Transport.DisableKeepAlives设置为true.

  • 这里也是一个有趣的参考:/sf/answers/1857625031/ (2认同)
  • @NimaMohammadi:如果你不读正文,那么连接就不能被重用,所以它必须被丢弃。 (2认同)