Warum funktioniert das Pufferlimit von Go Channel beim Schreiben/Lesen nicht richtig?

WBOY
Freigeben: 2024-02-09 10:30:19
nach vorne
458 Leute haben es durchsucht

为什么Go Channel的缓冲区不能正确限制写入/读取?

php-Editor Youzi beantwortet in diesem Artikel eine häufig gestellte Frage: „Warum schränkt der Puffer von Go Channel das Schreiben/Lesen nicht korrekt ein?“ In der Go-Sprache ist Channel eine Methode, die für Coroutinen verwendet wird. Wenn wir einen Kanal mit Puffer verwenden, erwarten wir, dass wir das Verhalten des Programms steuern können, indem wir die Anzahl der Schreib- oder Lesevorgänge begrenzen. Tatsächlich kann der Kanalpuffer die Anzahl der Schreib-/Lesevorgänge jedoch nicht direkt begrenzen. Die Ursachen und Lösungen für dieses Problem werden im Folgenden erläutert.

Frageninhalt

Ich versuche, über Kanäle zwischen zwei Go-Routinen zu kommunizieren. Zuerst habe ich den Ganzzahlkanal erstellt und ihn dann als Parameter an eine Go-Routine übergeben, die eine Zahlenfolge von 0 bis 10 ausgibt. Die Ausgabe dieser Programme ergibt keinen Sinn.

Dies ist der Hauptcode:

func worker(identifier string, ch chan<- int) {
    fmt.printf("entering worker %s\n", identifier)
    for i := 0; i < 10; i++ {
        fmt.printf("writing %d\n", i)
        ch <- i
    }

    fmt.printf("exiting worker %s\n", identifier)

    close(ch)
}

func main() {
    ch := make(chan int)
    go worker("1", ch)

    for v := range ch {
        fmt.printf("reading %d\n", v)
    }
}
Nach dem Login kopieren

Für diese Codeausführung habe ich die folgende Ausgabe erhalten:

entering worker 1
writing 0
writing 1
reading 0
reading 1
writing 2
writing 3
reading 2
reading 3
writing 4
writing 5
reading 4
reading 5
writing 6
writing 7
reading 6
reading 7
writing 8
writing 9
reading 8
reading 9
exiting worker 1
Nach dem Login kopieren

Beachten Sie, dass es zwei Schreibausführungen gibt, gefolgt von zwei Leseausführungen.

Später stelle ich eine Puffergröße ein, um die folgende Funktion zu erreichen:

func main() {
    ch := make(chan int, 3) // <= buffer
    go worker("1", ch)

    for v := range ch {
        fmt.printf("reading %d\n", v)
    }

}
Nach dem Login kopieren

Dann erhalten wir die folgende Ausgabe:

Entering worker 1
Writing 0
Writing 1
Writing 2
Writing 3
Writing 4
Reading 0
Reading 1
Reading 2
Reading 3
Reading 4
Writing 5
Writing 6
Writing 7
Writing 8
Writing 9
Reading 5
Reading 6
Reading 7
Reading 8
Reading 9
Exiting worker 1
Nach dem Login kopieren

Beachten Sie, dass wir jetzt 5 Schreibausführungen und dann 5 Leseausführungen haben.

Sobald wir den Code und die Ausgabe haben, stellt sich die letzte Frage: Warum verhalten sich diese Ausführungen so, wie sie es tun? Erstens: Sollte es nicht jeweils nur eine Zahl lesen und schreiben können? Warum liest und schreibt die zweite Ausführung darüber hinaus jedes Mal 5 statt 3 Zahlen (da das die Puffergröße ist)?

Problemumgehung

Sie geraten beim Drucken von Nachrichten und beim Lesen oder Schreiben von Zahlen aus dem Kanal in Verwirrung.

Bei einem Schreibvorgang erfolgt keine „Schreib“-Meldung. Sie treten irgendwann zwischen Schreibvorgängen auf. Ebenso erscheint die „Reading“-Meldung irgendwann zwischen den Lesevorgängen.

Hier ist eine Möglichkeit, das erste Code-Snippet anzuordnen, das die angezeigte Ausgabe erzeugt:

  • Versuche hauptsächlich zu lesen und dann zu blockieren.
  • Mitarbeiter druckt „Schreiben 0“.
  • Worker schreibt 0 und liest hauptsächlich.
  • Der Arbeiter druckt „Schreiben 1“.
  • Der Arbeitsthread hat versucht, 1 zu schreiben, wurde jedoch blockiert.
  • Drucken Sie hauptsächlich „Reading 0“.
  • Der Hauptinhalt ist 1.
  • Hauptdruck „Lesung 1“.
  • Versuche hauptsächlich zu lesen und dann zu blockieren.

Die Kontrolle wird auf diese Weise ständig zwischen Haupt- und Worker weitergegeben, wobei jeder zwei Nachrichten ausgibt, bevor er blockiert wird.

Ebenso kann Ihr zweiter Clip so arrangiert werden:

  • Versuche hauptsächlich zu lesen und dann zu blockieren.
  • Worker gibt „Writing 0“ aus und sendet 0 direkt an main.
  • Worker druckt „Writing 1“ und puffert 1.
  • Worker druckt „Writing 2“ und puffert 2.
  • Worker druckt „Writing 3“ und puffert 3.
  • Der Arbeitsthread gibt „Writing 4“ aus und blockiert Versuche, 4 zu senden.
  • main schließt den blockierten Lesevorgang ab und gibt „Reading 0“ aus.
  • main liest die gepufferte 1 und gibt „Reading 1“ aus.
  • main liest die gepufferten 2 und gibt „Reading 2“ aus.
  • main liest die gepufferten 3 und gibt „Reading 3“ aus.
  • main liest Worker blockiert 4 und gibt „Reading 4“ aus.
  • Versuche hauptsächlich zu lesen und dann zu blockieren.
  • Ausführung kehrt zum Arbeiter zurück...

Das obige ist der detaillierte Inhalt vonWarum funktioniert das Pufferlimit von Go Channel beim Schreiben/Lesen nicht richtig?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:stackoverflow.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage