2013-08-22 12 views
9

Ich bin neu in Go und habe ein Problem, die Nebenläufigkeit und Kanal zu verstehen.Go Nebenläufigkeit und Kanal Verwirrung

package main 

import "fmt" 

func display(msg string, c chan bool){ 
    fmt.Println("display first message:", msg) 
    c <- true 
} 

func sum(c chan bool){ 
    sum := 0 
    for i:=0; i < 10000000000; i++ { 
     sum++ 
    } 
    fmt.Println(sum) 
    c <- true 
} 

func main(){ 
    c := make(chan bool) 

    go display("hello", c) 
    go sum(c) 
    <-c 
} 

Die Ausgabe des Programms ist:

display first message: hello 
10000000000 

Aber ich dachte, es sollte nur eine Zeile sein:

display first message: hello 

So in der Hauptfunktion, < -c ist es blockiert und wartet darauf, dass die anderen zwei Routinen Daten an den Kanal senden. Sobald die Hauptfunktion die Daten von c empfängt, sollte sie fortfahren und beenden.

Anzeige und Summe laufen gleichzeitig und Summe dauert länger so Anzeige sollte wahr c schicken und das Programm sollte beenden, bevor Summe beendet ...

Ich bin nicht sicher, ich es klar zu verstehen. Könnte mir jemand dabei helfen? Vielen Dank!

+0

Wie tux21b andeutet, liegt das wahrscheinlich an 'runtime.GOMAXPROCS'. Bump es, und Sie können einen Unterschied sehen. – dyoo

Antwort

4

Die genaue Ausgabe Ihres Programms ist nicht definiert und hängt vom Scheduler ab. Der Scheduler kann frei zwischen allen nicht blockierten Gououtlines wählen. Es versucht, diese Goroutines gleichzeitig auszuführen, indem die aktuelle Goroutine in sehr kurzen Zeitintervallen umgeschaltet wird, so dass der Benutzer das Gefühl hat, dass alles gleichzeitig passiert. Darüber hinaus kann es auf mehreren CPUs auch mehr als eine Goroutine parallel ausführen (wenn Sie ein Multicore-System haben und runtime.GOMAXPROCS erhöhen). Eine Situation, die zu Ihrem Ausgang führen könnte, ist:

  1. main erstellt zwei goroutines
  2. der Planer wählt zu einem des neuen goroutines wechseln sofort und wählt display
  3. display druckt die Nachricht und blockiert durch der Kanal sendet (c <- true), da es noch keinen Empfänger gibt.
  4. der Scheduler wählt sum nächsten
  5. die Summe berechnet wird, und werden auf dem Bildschirm
  6. der Scheduler wählt, um nicht wieder das sum goroutine (es wurde bereits verwendet, um eine Menge Zeit) und fährt mit display
  7. auszuführen
  8. display sendet den Wert an den Kanal
  9. der Scheduler Haupt nächsten
  10. Haupt beendet und alle goroutines zerstört werden, laufen wählt

Aber das ist nur eine mögliche Ausführungsreihenfolge. Es gibt viele andere und einige von ihnen werden zu einer anderen Ausgabe führen. Wenn Sie nur das erste Ergebnis drucken und danach das Programm beenden möchten, sollten Sie wahrscheinlich result chan string verwenden und Ihre main Funktion ändern, um fmt.Println(<-result) zu drucken.

+0

Danke für die Klarstellung. In Schritt 3 wird die Anzeige durch den Sendekanal blockiert, da kein Empfänger vorhanden ist. Eh ... Wann ist der Empfänger bereit? – SteelwingsJZ

+1

Der Kanal ist synchron, was bedeutet, dass sowohl der Empfänger als auch der Sender bereit sein müssen, um den Wert zu übertragen.Wenn eine Goro-Routine zuerst 'c <- true' ausführt, wird sie blockiert, bis eine andere goroutine '<-c' ausführt. Es ist aber auch möglich, dass eine Goroutine, die '<-c 'ausführt, blockiert wird, bis in einer anderen Goroutine ein übereinstimmendes' c <- true' vorliegt. – tux21b

+0

Nur ein Kommentar. Soweit ich weiß, ist der Go-Scheduler in der aktuellen Version nicht präventiv. Sobald eine Goroutine die CPU hat, wird sie nicht zu einer anderen wechseln, bis sie blockiert ist (aufgrund von E/A, Kanal, Mutex usw.). Wenn die Summe zuerst ausgeführt wird, wird sie die CPU ausschließlich verwenden, bis sie vom Kanal blockiert wird (ich bin mir nicht sicher, ob fmt.Println einen CPU-Schalter erzeugen kann). Ein Preemptive Scheduler ist für Go 1.2 geplant, habe ich gelesen. Wenn GOMAXPROCS nicht 1 ist, wird die andere Goroutine natürlich einen anderen SO-Level-Prozess verwenden und von der SO geplant werden. Weitere Informationen finden Sie hier: http://dominik.honnef.co/go-tip/2013-08-15/ – siritinga