ioutil.ReadAll 导致 goroutine 泄漏
ioutil.ReadAll leads to goroutine leak
为什么我在终止前有多个 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())
}
输出:
#Goroutines: 1
#Goroutines: 3
默认的 http 传输 maintains a connection pool。
DefaultTransport is the default implementation of Transport and is used by DefaultClient. It establishes network connections as needed and caches them for reuse by subsequent calls.
每个连接至少由一个协程管理。但这不是泄漏,您只是不耐烦。如果你等待的时间足够长,你会看到连接最终关闭并且 goroutine 消失了。默认空闲超时为 90 秒。
如果您想尽快关闭连接,请将 http.Request.Close or http.Transport.DisableKeepAlives 中的任何一个设置为 true。
为什么我在终止前有多个 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())
}
输出:
#Goroutines: 1
#Goroutines: 3
默认的 http 传输 maintains a connection pool。
DefaultTransport is the default implementation of Transport and is used by DefaultClient. It establishes network connections as needed and caches them for reuse by subsequent calls.
每个连接至少由一个协程管理。但这不是泄漏,您只是不耐烦。如果你等待的时间足够长,你会看到连接最终关闭并且 goroutine 消失了。默认空闲超时为 90 秒。
如果您想尽快关闭连接,请将 http.Request.Close or http.Transport.DisableKeepAlives 中的任何一个设置为 true。