2013-04-29 32 views
6

我正在學習使用,我的第一個項目之一是一個簡單的ping腳本。基本上我想ping一堆網址,並在每個人的響應等待XXX秒數然後再次ping。下面是刪節代碼:在goroutines內部啓動goroutines是否可以接受?

func main() { 
    // read our text file of urls 
    f, err := ioutil.ReadFile(urlFile) 
    if err != nil { 
     log.Print(err) 
    } 

    urlStrings := []string{} 
    urlStrings = strings.Split(string(f), "\n") 

    for _, v := range urlStrings { 
     go ping(v) 
    } 

    // output logs to the terminal 
    // channel is global 
    for i := range c { 
     fmt.Println(i) 
    } 
} 

func ping(url string) { 
    // for our lag timer 
    start := time.Now() 

    // make our request 
    _, err := http.Get(url) 

    if err != nil { 
     msg := url + " Error:" + err.Error() 

     fmt.Println(msg) 

     c <- msg 
     reportError(msg) 
    } else { 
     lag := time.Since(start) 
     var msg string 

     // running slow 
     if lag > lagThreshold*time.Second { 
      msg = url + " lag: " + lag.String() 
      reportError(msg) 
     } 

     msg = url + ", lag: " + lag.String() 
     c <- msg 
    } 

    time.Sleep(pingInterval * time.Second) 
    go ping(url) // is this acceptable? 
} 

在我的Get請求我以前呼籲推遲res.Body.Close(),但是這是panicing後的應用程序運行一段時間。我認爲延遲無法在響應中調用Close(),直到goroutine被垃圾收集並且res不再存在。

這讓我想到如果通過調用goroutine內部的goroutine是最佳做法,或者如果我導致函數永不退出,那麼只有在goroutine被垃圾收集後纔會調用延遲。

+0

從其他goroutines產生goroutines應該沒有任何問題,但是有什麼理由不在這種情況下使用循環嗎? – 2013-04-29 21:28:12

+0

@JamesHenstridge I在程序循環中沒有這樣做,所以我不必在每次請求返回之前等待每個請求返回。我試圖使用併發性,因此每個ping週期都是基於它自己的滯後時間而獨立的。 – ARolek 2013-04-29 22:52:50

+0

我指的是'ping()'goroutine在退出前產生另一個goroutine的部分。如果你在'ping()'中放置一個循環,你會得到同樣的效果。 – 2013-04-29 23:26:21

回答

11

這很好。從另一個goroutine調用goroutine是完全可以接受的。調用的goroutine將會退出,新的goroutine將繼續進行。

7

從goroutine內部新建一個goroutine本身就非常好。

但我懷疑這是對您的問題最簡單和最乾淨的解決方案。 我想你的第一個版本做了明顯的事情,並在無盡的循環中ping每個URL。而且這個叮咬推遲:當功能返回時,延遲呼叫被執行。 (這與一個goroutine beeing沒有任何關係,「垃圾收集,實際上goroutines剛剛結束,沒有收集)。在一個永無止境的循環中,你永遠不會回來,你只積累那些永不執行的守衛的召喚。 res.Body你耗盡內存/什麼,看到了恐慌。

defer res.Body.Close是一個很好的習慣用法,但不是一個死循環中。

我會嘗試你的第一個版本,並直接執行res.Body 。關閉nil錯誤路徑

+0

如果我不調用res.Body.Close()也會使用內存使用情況,或者將res放棄? – ARolek 2013-04-29 22:54:38

+0

您**必須**致電res.Body.Close。由於某種原因記錄在案。 (否則你的代碼會泄漏。) – Volker 2013-04-30 07:40:27

+0

如果我沒有把它當作我以上所做的var來處理,該怎麼辦? _,err:= http.Get(url)會泄露嗎? – ARolek 2013-04-30 17:34:56