2016-06-05 14 views
0

Ich bin verwirrt von einigen seltsamen Verhalten, das ich mit SMTP aus einer Goroutine gefunden.Seltsames Verhalten mit SMTP in Goroutine

Beim Versuch, eine E-Mail mit dem folgenden Code zu senden, startet meine SendMail-Funktion (ich kann eine Protokollnachricht sehen), aber nie abgeschlossen. Es hängt einfach.

Wenn ich jedoch einen weiteren Anruf zu SendMail hinzufüge - zwei E-Mails werden beide erfolgreich gesendet.

func main() { 
    go SendEmail("TEST") 
    SendEmail("TEST") 
    for {} 
    } 

Kann jemand erklären, was vor sich geht?

NB Dies ist eine sehr vereinfachte Version einer Aufgabe geplant, damit die while-Schleife

-Code E-Mail senden:

func SendEmail(message string) { 
    log.Print("Sending email") 
    from, password, to := "[email protected]", "PASSWORD", "[email protected]" 

    err := smtp.SendMail(
    "smtp.gmail.com:587", 
    smtp.PlainAuth("", from, password, "smtp.gmail.com"), 
    from, 
    []string{to}, 
    []byte(message), 
    ) 
if err != nil { 
    log.Fatal(err) 
} 
    log.Print("Sending complete") 
} 

Dank!

+1

Was passiert, wenn Sie 'runtime.Gosched()' in die leere for-Schleife einfügen? – ctcherry

+3

Ersetzen Sie 'for {}' durch 'select {}'. Es ist wahrscheinlich ein Scheduler-Problem, das jemand anderes ausführlicher erklären wird :) – joshlf

+0

Mögliches Duplikat von [Golang http Server blockiert, wenn eine Goroutine der Endlosschleife beginnt] (http://stackoverflow.com/questions/26624959/golang-http-server-blocks-when-starts-eine-goroutine-of-endless-loop) –

Antwort

1

Sie sollten Ihre durch eine select{} ersetzen. Erstellen Sie niemals eine leere .

Die for{} erstellt eine Schleife, die für immer dreht, aber da es keine Funktionsaufrufe (oder genauer Stapelprüfungen und/oder Zuweisungen) in der Schleife gibt, kann der Scheduler die Hauptgoroutine nicht entplanen verhindert, dass Ihre andere Goroutine geplant wird. (Dies wird wahrscheinlich auch eine ganze CPU essen, weil Sie einen OS-Thread mit einem Busy-Looping betreiben)

Siehe meinen Hinweis zu GOMAXPROCS am Ende.

von SendEmail("TEST") direkt nach dem go SendEmail("TEST") der Laufzeit Aufruf bekommt eine Chance (oder besser gesagt, mehr Chancen) Ihre andere goroutine zu planen, auszuführen, bevor Sie die for{} Schleife bekommen.

Mit einer leeren Auswahl (select{}) wird die Hauptgoroutine auf unbestimmte Zeit warten, ohne eine CPU zu verbrauchen und stattdessen wird sie direkt dem Scheduler übergeben.

über GOMAXPROCS

Wenn Ihr GOMAXPROCS ist 1 (Standard vor Go 1.5) Sie werden nur einen einzigen OS-Thread haben (zumindest für goroutines ausgeführt wird), die alle andere goroutines nicht ausgeführt werden wird, wenn Sie eine Busy-Schleife haben. Wenn Sie GOMAXPROCS> 1 haben, könnte die Runtime noch andere Gloutines planen, da es mehr als einen Thread zum Ausführen von Goroutines gibt, aber Sie sollten sich nicht darauf verlassen. Stattdessen sollten Sie alle Busy-Loops entfernen.