2016-03-28 4 views
2

Ich habe gerade ein Tutorial zu gehen und folgen Sie lernen gestartet, die das folgende Beispiel auf goroutines enthält:Goroutine Beispiel explaination benötigt

package main 

import (
    "fmt" 
    "runtime" 
) 

func say(s string) { 
    for i := 0; i < 5; i++ { 
     runtime.Gosched() 
     fmt.Println(s) 
    } 
} 

func main() { 
    go say("world") // create a new goroutine 
    say("hello") // current goroutine 
} 

heißt es, dass "runtime.Gosched()Mittel, um die CPU lassen führe andere Goroutinen aus und komm irgendwann zurück. ". Die folgende Ausgabe wird unter dem gegebenen Beispiel:

hello 
world 
hello 
world 
hello 
world 
hello 
world 
hello 

Jedoch, wenn ich dieses Beispiel auf meinem Rechner laufen mit go run ich

bekommen
hello 
world 
world 
world 
world 
world 
hello 
hello 
hello 
hello 

meine Version von Go ist go version go1.6 darwin/amd64.

Eigentlich verstehe ich auch kein Ergebnis! Warum ist es nicht einfach

hello 

? Wie ich verstehe, Go-Programme beenden, nachdem die letzte Anweisung des Programms ausgeführt wird, so würde ich denken, dass nach say() als Goroutine ausgeführt wird und seine Ausführung verzögert ist, führt das Programm nächste say() als eine normale Funktion, drucken "Hallo" und dann verlassen.

Also welches Ergebnis ist das richtige und warum?

+0

Überprüfen Sie dies. [verwandte Frage] (http://stackoverflow.com/questions/13107958/what-exactly-does-runtime-gosched-do) – Spartan

Antwort

3

Die erste Ausgabe wird von einer einzelnen Kernmaschine generiert. Die zweite könnte durch eine Multicore-Sequenz erzeugt werden.

say ist eine Funktion mit einer for-Schleife innerhalb, die 5 mal iteriert. Es ist in der Tat eine gewöhnliche Funktion, aber es gibt einen Aufruf an Gosched darin. Was Gosched tut, ist, dass es der Laufzeit sagt, die aktuelle goroutine anzuhalten und stattdessen eine andere wartende goroutine zu starten. Dies wird genannt, was ergibt.

Erklären erste Ausgabe

Dies ist die Ausgabe, die Sie erwarten können, in einer Single-Core-Maschine zu bekommen. Schritt für Schritt gehen,

go say("world")

Bei diesem Schritt beginnt die Laufzeit den say("world") Anruf auf einem separaten goroutine Ausführung und den Haupt goroutine fortzusetzen. Aber die Maschine hat nur einen einzigen Kern. Also können beide Goroutinen nicht parallel laufen. Die neue Goroutine (z. B. gr A) muss warten, bis die laufende Hauptgoroutine (z. B.) endet oder pausiert (yeilds). Also wartet es. Haupt goroutine beginnt say("hello")

Jetzt ausführen, während er durch die say Funktion von gr B Laufzeit geht trifft runtime.Gosched()

Der Gosched Anruf wird wie pausieren. Er sagt der Laufzeit, dass er mich pausiert und eine andere Gorroutine einplant, die wartet. So plant die Laufzeit die gr A.Es beginnt, von wo aus sie wartet, das ist,

say("world")

Jetzt gr A führt, bis er seine eigenen runtime.Gosched() erfüllt. gr A pausiert. wacht auf und fängt an zu laufen von wo es wegging. Die Aussage nach runtime.Gosched() soll "Hallo" drucken. So wird "Hallo" gedruckt. wird fortgesetzt und tritt in die nächste Iteration seiner for-Schleife ein. Erfüllt Gosched. Pausen. gr A startet neu. Druckt "Welt". Ich denke, man kann sehen, wie es 5 Mal vorgeht, bis es die gegebene Ausgabe druckt.

der zweite Ausgang

Erklären Wenn Ihre Maschine mehr als einen Kern aufweist, können die goroutines parallel laufen. Ihre Ausgabe erhalten Sie, wenn sie es tut.

Jetzt, wenn go say("world") heißt gr A muss nicht warten, bis gr B endet. Es kann sofort auf einem anderen Kern beginnen. Wenn also Gosched aufgerufen wird, könnte es keine wartenden Göroutinen geben. Wenn der aktuelle angehalten wird, startet er sofort auf einem anderen Kern.

So können Sie in einer Multicore-Maschine nicht die Reihenfolge garantieren, in der die Wörter gedruckt werden. Wenn Sie das Programm viele Male ausführen, werden Sie wahrscheinlich auch andere Befehle sehen.

Sie können GOMAXPROCs auf 1 setzen und sehen, wie das Programm auf einer einzelnen Kernmaschine ausgeführt wird.

func main() { 
    runtime.GOMAXPROCS(1) 

    go say("world") // create a new goroutine 
    say("hello") // current goroutine 
} 

Dann sehen Sie den ersten Ausgang.

+0

Wenn ich genug Kerne habe und die Ausführung Flow trifft 'Gosched()' kann es tatsächlich nein Warten, habe ich es richtig verstanden? So sagt 'Gosched()' eine Art Sprichwort "wenn du weiter laufen kannst, sonst kannst du hier zu einer anderen Goroutine wechseln"? – xaxa

+0

Ich denke, es wird immer die aktuelle Goroutine pausieren. Und wähle eine wartende Gorroutine zur Ausführung aus. Wenn die einzige wartende Goroutine diejenige ist, die gerade pausiert hat, wird sie erneut ausgewählt. Also im Grunde, was du gesagt hast. –