Heim  >  Artikel  >  Backend-Entwicklung  >  Wie ist bei der Verwendung von Kanälen die Ausführungsreihenfolge von Goroutinen?

Wie ist bei der Verwendung von Kanälen die Ausführungsreihenfolge von Goroutinen?

王林
王林nach vorne
2024-02-09 13:48:091218Durchsuche

使用通道时,goroutine 的执行顺序是什么?

php-Editor Baicao ist hier, um eine häufig gestellte Frage zu beantworten: „Wie ist die Ausführungsreihenfolge von Goroutinen bei der Verwendung von Kanälen?“ In der Go-Sprache sind Goroutinen leichte Threads, die gleichzeitig ausgeführt werden können. Wenn Kanäle für die Kommunikation zwischen Coroutinen verwendet werden, blockieren die Empfangs- und Sendevorgänge des Kanals, das heißt, sie warten auf den Abschluss der Operationen anderer Coroutinen. Wenn daher mehrere Goroutinen gleichzeitig einen Kanal betreiben, ist ihre Ausführungsreihenfolge ungewiss und hängt von der Planung jeder Coroutine ab. Dies bedeutet, dass es unmöglich ist, zu bestimmen, welche Goroutine zuerst und welche später ausgeführt wird. Dies wird vom Scheduler der Go-Sprache bestimmt.

Frageninhalt

Wie ist die Ausführungsreihenfolge von Goroutinen bei Verwendung von Kanälen? Ich denke, dass das Schreiben oder Lesen des Kanals die aktuelle Goroutine stoppt. Aber mein Testcode folgt dieser Regel nicht:

func main() {
    ch := make(chan int)
    go sum(ch, 3)
    fmt.Println("Write number: 10")
    ch <- 10
    fmt.Println("Write number: 20")
    ch <- 20
    fmt.Println("Write number: 30")
    ch <- 30

    fmt.Println("Finish main")
}

func sum(ch chan int, len int) {
    fmt.Println("Func 'sum' start")

    sum := 0
    for i := 0; i < len; i++ {
       fmt.Println("For start")
       num := <-ch
       fmt.Printf("Read from ch: %d\n", num)
       sum += num
       fmt.Println("For finish")
    }

    fmt.Printf("Sum: %d\n", sum)
}

Wie diese App meiner Meinung nach funktioniert:

1.Kanal erstellen

2. Erstellen Sie eine Goroutine (nicht gestartet, nur initialisiert)

3. Drucken: Notieren Sie die Zahl: 10

4. Auf Kanal 10 aufnehmen. Tastenfunktionen sperren.

5. Das Wichtigste ist, blockiert zu werden. Starten Sie die Sum-Goroutine.

6. Summierungsfunktion drucken: Func 'sum' start

7. Die Summierungsfunktion läuft in einer Schleife und gibt aus: „Zu beginnen“

8. Lesen Sie die Zahl 10 aus „ch“ und drucken Sie: „Read from ch: 10“

9. Nächster Schritt. Drucken Sie: „Fertig“ und fahren Sie mit der nächsten Iteration fort.

10. Drucken Sie: „beginnt mit“ und versuchen Sie, „mit“ zu schreiben. Aber der Kanal ist leer. Stoppen Sie das Kontingent und betreten Sie die Hauptzeile

...und immer wieder.

Dann möchte ich sehen:

Write number: 10
Func 'sum' start
For start
Read from ch: 10
For finish
For start
Write number: 20
Read from ch: 20
For finish
For start
Write number: 30
Read from ch: 30
For finish
Sum: 60
Finish main

Aber ich habe gesehen:

Write number: 10
Func 'sum' start
For start
Read from ch: 10
For finish
For start
Write number: 20
Write number: 30
Read from ch: 20
For finish
For start
Read from ch: 30
For finish
Sum: 60
Finish main

Wie ist das möglich? Die Hauptfunktion schreibt zweimal auf den Kanal, ohne zu lesen.

Auch wenn Sie die Anzahl der Anrufe ändern für:

go sum(ch, 2)

Ich verstehe den Fehler nicht. Aber niemand hat die letzte Nachricht gelesen

Beispiel: vor dieser Nachricht.

Lösung

Goroutinen laufen gleichzeitig. Auf Systemen mit mehreren Kernen können sie parallel laufen. Die Details hängen von der Scheduler-Implementierung in der Go-Laufzeit ab. Mit Ausnahme synchroner Vorgänge wie der Kanalkommunikation geschehen die Dinge in jeder Hinsicht in zufälliger Reihenfolge.

Dies ist nicht der Fall und geschieht auch nicht (solange der Kanal nicht gepuffert ist). Der Println-Aufruf erfolgt vor dem Sendevorgang und die Haupt-Goroutine blockiert nach dem Drucken, bis die Summen-Goroutine empfangsbereit ist.

Ob Sie „Read from ch: 30“ aufgedruckt sehen, ist ebenfalls zufällig. Der entsprechende Empfangsvorgang muss ausgeführt werden, da main blockiert, bis dies geschieht. Allerdings kann main vor Println zurückkehren, nachdem der Empfang erfolgt ist, und das Programm wird sofort beendet, wenn main zurückkehrt, unabhängig davon, ob andere Goroutinen vorhanden sind. Wenn der Kanal gepuffert ist, erhöht sich die Wahrscheinlichkeit, dass dies geschieht.

Das ist nicht der Fall. Wenn nur zwei Empfänger vorhanden sind, kommt es immer zu einem Deadlock: https://go.dev/play/p/ qFVh529mkqR

Das obige ist der detaillierte Inhalt vonWie ist bei der Verwendung von Kanälen die Ausführungsreihenfolge von Goroutinen?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen