Frage

Umgebung: OS X 10.8, GO 1.0.2

Ich erstelle einen Kanal mit Puffergröße 2. Wenn ich dreimal Kanal schreibe, wird ein Fehler ausgeführt:

Throw: Alle Goroutinen schlafen - Deadlock!

Natürlich ist es richtig.

ABER Wenn ich in den Goroutinen vier oder öfter in den Goroutinen schreibe, funktioniert es gut, warum? Die Kapazität des Kanals beträgt 2, warum goroutines das ignorieren oder die Kapazitätseinstellung vergessen? Ich kommentiere die Read-Kanal-Codes, sodass niemand den Kanal liest und die Kapazität speichert. Ich benutze auch Time.

Bitte überprüfen Sie die folgenden Codes: Paket -Haupt

//import "fmt"

func main() {
    c := make(chan int, 2)
    /*c <- 1
    c <- 2
    c <- 3*/
    for i:=0; i<4; i++ {
        go func(i int) {
            c <- i
            c <- 9
            c <- 9
            c <- 9
        }(i)
    }
    time.Sleep(2000 * time.Millisecond)

    /*for i:=0; i<4*2; i++ {
        fmt.Println(<-c)
    }*/
}

Würde jemand bitte ein paar Hits geben? danke Leute.

War es hilfreich?

Lösung

Wenn ein Kanal gepuffert ist, bedeutet dies, dass er erst blockiert wird, wenn der Puffer voll ist. Sobald der Puffer voll ist, blockiert die sendende Goroutine, wenn es versucht, den Kanal hinzuzufügen.

Dies bedeutet, dass dies blockiert wird:

c := make(chan int)
c <- 1          // Block here, this is unbuffered !
println(<-c)

Und das wird Auch Block:

c := make(chan int, 2)
c <- 1
c <- 2
c <- 3           // Block here, buffer is full !
println(<-c)

Aber die Punkt von Goroutines und Kanal ist genau, um die Dinge gleichzeitig auszuführen, daher wird dies funktionieren:

c := make(chan int)
go func() { c <- 1; }() // This will block in the spawned goroutine until...
println(<-c)            // ... this line is reached in the main goroutine

Und ähnlich:

c := make(chan int, 2)
go func() {  // `go ...` spawns a goroutine
    c <- 1   // Buffer is not full, no block
    c <- 2   // Buffer is not full, no block
    c <- 3   // Buffer is full, spawned goroutine is blocking until...
}()
println(<-c) // ... this line is reached in the main goroutine

In Ihrem Beispiel spawnen Sie vier verschiedene Goroutinen, die alle vier Zahlen in denselben gepufferten Kanal schreiben. Da der Puffer 2 <16 ist, werden sie am Ende blockieren

Aber der Kern der Sache ist, dass die GO -Richtlinie darauf ist Warten Sie nur auf die Haupt -Goroutine:

Die Programmausführung beginnt mit der Initialisierung des Hauptpakets und dann auf die Funktion der Funktion. Wenn die Funktion der Funktion zurückgibt, verlässt das Programm. Es wartet nicht, dass andere (Nicht-Main-) Goroutinen abgeschlossen sind.

Dies bedeutet, dass in Ihrem ersten Beispiel die hauptsächlich Goroutine blockierte, als sie die Linie erreichte c <- 3. Da keine andere Goroutine etwas tun konnte, was möglicherweise entsperren konnte, erkannte die Laufzeit, dass das Programm abgestimmt war und einen Fehler gemeldet hatte.

In Ihrem zweiten Beispiel jedoch, hervorgebracht Goroutines blockiert, während die Hauptdauer ruhig fortgesetzt wird, bis sie das Ende seiner Ausführung erreicht. Zu diesem Zeitpunkt werden alle (blockierten) Goroutinen still getötet, und es wird kein Fehler gemeldet.

Andere Tipps

val hat eine gute Antwort gegeben. Ich möchte einen zusätzlichen Tipp hinzufügen, den ich nützlich gefunden habe.

Verwenden Sie beim Lernen, Goroutinen zu verwenden, mit Null gepufferten Kanälen. Auf diese Weise erhalten Sie, wenn Sie einen Fehler machen, sofort einen Deadlock, aus dem Sie lernen können. Sie müssen lernen, wie man Code schreibt, der nicht zugänglich ist. Dies bedeutet, dass Tricks wie keine zyklischen Abhängigkeiten in den Kunden-Server-Beziehungen gelernt werden (vorausgesetzt, Ihre Goroutinen sind als Clients oder Server geschrieben).

Das Denken über das Netzwerk ohne Pufferung ist einfacher, obwohl dies zunächst möglicherweise nicht offensichtlich ist.

Pufferung ist wirklich nützlich, sollte aber als Mittel zur Verbesserung der Leistung angesehen werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top