2014-01-08 58 views
2

我用夠程實現http.Get超時,然後我發現數量一直在穩步上升夠程,當它到達1000左右時,程序將退出golang HTTP超時和積累夠程

代碼:

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()) 
} 

http://play.golang.org/p/SzGTMMmZkI

+0

請務必將相關代碼**放入**您的問題中。一個小提琴的鏈接很好,但作爲補充。 –

+0

@dystroy ok,我改變了 – Specode

回答

2

初始化您瓚與1,而不是0:

ch := make(chan Response, 1)

然後刪除關閉並延遲ch的延遲塊。

參見:http://blog.golang.org/go-concurrency-patterns-timing-out-and

以下是我認爲正在發生的事情:

  1. 在5秒超時後,timeoutHttpGet返回
  2. 的延遲語句運行,關閉通道,然後將其設置爲無
  3. go例程它開始執行實際的讀取結束並嘗試將其數據發送到ch
  4. 但ch爲零,因此不會收到任何內容,prev enting精加工而成,從而防止走常規精加工而成

這句話我假設你正在設置ch = nil因爲之前你有,你會得到運行時的恐慌,因爲這是發生在你試圖寫一個封閉通道,如the spec所述。

給出一個1的緩衝區意味着提取去程序可以發送給它,而不需要接收器。如果處理程序由於超時而返回,則以後所有內容都將被垃圾回收。

+0

非常感謝! – Specode