2013-04-29 10 views
6

Ich lerne gerade jetzt mit und eines meiner ersten Projekte ist ein einfaches Ping-Skript. Im Wesentlichen möchte ich eine Reihe von URLs pingen, und auf die Antwort von jedem warten XXX Anzahl von Sekunden, dann erneut pingen. Hier ist der gekürzte Code:Ist das Starten von Goroutines innerhalb von Goroutines akzeptabel?

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? 
} 

Auf meiner Get-Anfrage ich vorher rief aufschieben res.Body.Close(), aber das war panicing nach der App für eine Weile lief. Ich nahm an, dass die Verzögerung die Close() auf der Antwort nicht aufrufen konnte, bis die Goroutine Müll gesammelt worden war und die res nicht mehr existierte.

Das brachte mich zum Nachdenken, ob das Aufrufen einer Goroutine innerhalb einer Goroutine Best Practice war oder ob ich die Funktion niemals beenden würde, und dann würde ein Defer nur aufgerufen werden, sobald die Goroutine Müll gesammelt wurde.

+0

Es sollte kein Problem geben, Glautines von anderen goroutines zu laichen, aber gibt es irgendeinen Grund, nicht nur eine Schleife in diesem Fall zu verwenden? –

+0

@JamesHenstridge I Ich mache das nicht in einer prozeduralen Schleife, so dass ich nicht auf jede Anfrage warten muss, bevor ich die nächste anrufe. Ich versuche, die Nebenläufigkeit zu verwenden, so dass jeder Ping-Zyklus basierend auf seiner eigenen Verzögerungszeit unabhängig ist. – ARolek

+0

Ich bezog mich auf den Teil, wo die 'ping()' Goroutine kurz vor dem Beenden eine weitere Goroutine erzeugt. Wenn Sie eine Schleife in "ping()" einfügen, erhalten Sie den gleichen Effekt. –

Antwort

11

Das ist in Ordnung. Es ist durchaus akzeptabel, eine Goroutine von einer anderen Goroutine aus aufzurufen. Die aufrufende Goroutine wird immer noch verlassen und die neue Goroutine wird auf ihren fröhlichen Weg gehen.

7

Eine neue Goroutine innerhalb einer Goroutine zu spannen ist per se völlig in Ordnung.

Aber ich bezweifle, dass dies die einfachste und sauberste Lösung für Ihr Problem ist. Ich vermute, dass Ihre erste Version das Offensichtliche getan hat und jede URL in einer Endlosschleife pingt. Und diese Bisse verzögern: Aufgeschobene Aufrufe werden ausgeführt, sobald die Funktion zurückgibt. (Das hat nichts mit einer Goroutine zu tun, die "Müll sammelt; eigentlich enden die Gorutiere einfach, die werden nicht eingesammelt.) In einer Endlosschleife kommt man nie zurück, man sammelt nur abgelehnte Anrufe, die nie ausgeführt werden. Man schließt also nie alle offenen res.Body und Sie laufen aus dem Speicher/was auch immer, und eine Panik sehen.

Doing defer res.Body.Close eine schöne Idiom ist, aber nicht in einer Endlosschleife.

ich würde versuchen, die erste Version und direkt ausführen res.Body Schließen Sie auf dem Null-Fehlerpfad

+0

Wenn ich Res nicht aufrufen. Body.Close() wird auch die Speicherbelegung Verbindung, oder wird die res verworfen werden? – ARolek

+0

Sie ** müssen ** rufen res.Body.Close. Es ist aus irgendeinem Grund dokumentiert. (Ihr Code würde sonst undicht werden.) – Volker

+0

Was passiert, wenn ich es nicht zu einer Var falle, wie ich oben tue? _, err: = http.Get (URL) wird das Leck? – ARolek