我使用goroutines实现http.Get超时,然后我发现goroutines的数量一直在稳步上升,当达到1000个左右时,程序就会退出
代码:
package main
import (
"errors"
"io/ioutil"
"log"
"net"
"net/http"
"runtime"
"time"
)
// timeout dialler
func timeoutDialler(timeout time.Duration) func(network, addr string) (net.Conn, error) {
return func(network, addr string) (net.Conn, error) {
return net.DialTimeout(network, addr, timeout)
}
}
func timeoutHttpGet(url string) ([]byte, error) {
// change dialler add timeout support && disable keep-alive
tr := &http.Transport{
Dial: timeoutDialler(3 * time.Second),
DisableKeepAlives: true,
}
client := &http.Client{Transport: tr}
type Response struct {
resp []byte
err error
}
ch := make(chan Response, 0)
defer func() {
close(ch)
ch = nil
}()
go func() {
resp, err := client.Get(url)
if err != nil {
ch <- Response{[]byte{}, err}
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
ch <- Response{[]byte{}, err}
return
}
tr.CloseIdleConnections()
ch <- Response{body, err}
}()
select {
case <-time.After(5 * time.Second):
return []byte{}, errors.New("timeout")
case response := <-ch:
return response.resp, response.err
}
}
func handler(w http.ResponseWriter, r *http.Request) {
_, err := timeoutHttpGet("http://google.com")
if err != nil {
log.Println(err)
return
}
}
func main() {
go func() {
for {
log.Println(runtime.NumGoroutine())
time.Sleep(500 * time.Millisecond)
}
}()
s := &http.Server{
Addr: ":8888",
ReadTimeout: 15 * time.Second,
WriteTimeout: 15 * time.Second,
}
http.HandleFunc("/", handler)
log.Fatal(s.ListenAndServe())
}
最佳答案
用 1 而不是 0 初始化你的 chan:
ch := make(chan Response, 1)
并删除关闭和 nils ch 的 defer block 。
参见:http://blog.golang.org/go-concurrency-patterns-timing-out-and
这是我认为正在发生的事情:
- 5秒超时后,timeoutHttpGet返回
- defer 语句运行,关闭 ch 并将其设置为 nil
- 它开始执行实际获取的 go 例程完成并尝试将其数据发送到 ch
- 但是 ch 为零,因此不会收到任何内容,从而阻止该语句完成,从而阻止 go 例程完成
我假设您正在设置 ch = nil
,因为在此之前,您会遇到运行时 panic ,因为当您尝试写入关闭的 channel 时会发生这种情况,如 the spec 所描述的。
将 ch 的缓冲区设置为 1 意味着 fetch go 例程可以向其发送数据而无需接收器。如果处理程序由于超时而返回,则所有内容稍后都会被垃圾收集。
关于http - golang http超时和goroutines累积,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20990332/