Heim >Backend-Entwicklung >Golang >Detaillierte Erklärung des Golang-Kanals Chan

Detaillierte Erklärung des Golang-Kanals Chan

藏色散人
藏色散人nach vorne
2020-11-09 15:40:542642Durchsuche

Die Kolumne Golang-Tutorial stellt Ihnen Golang über den Kanal Chan vor. Ich hoffe, dass sie Freunden, die es brauchen, hilfreich sein wird!

Detaillierte Erklärung des Golang-Kanals Chan

Schauen wir uns zunächst Threads an, die auf Golang auch Goroutine genannt werden.

Bevor wir diesen Artikel lesen, müssen wir Parallelität und Parallelität verstehen. Golangs Thread ist ein Parallelitätsmechanismus, keine Parallelität. Sie können im Internet nach den Unterschieden suchen. Es gibt viele Einführungen online.

Schauen wir uns zuerst ein Beispiel an

import(
         "fmt"
)

funcmain(){

    go fmt.Println("1")
    fmt.Println("2")    
}

In Golang können Sie einen Thread erstellen, indem Sie das Schlüsselwort go gefolgt von einer Funktion verwenden. Die letztere Funktion kann eine vorab geschriebene Funktion oder eine anonyme Funktion sein. Der obige Code erstellt eine anonyme Funktion und übergibt außerdem einen Parameter i. Das i in Klammern unten ist der tatsächliche Parameter a ein formaler Parameter.

Kann der obige Code also wie erwartet 1, 2 und 3 ausgeben? Ich sage Ihnen, nein, das Programm kann nur 2 ausdrucken. Ich werde unten den richtigen Code veröffentlichen

funcmain(){    var i=3    go func(a int) {        fmt.Println(a)
        fmt.Println("1")
    }(i)
    fmt.Println("2")}

Ich habe am Ende nur eine Codezeile hinzugefügt, um den Hauptthread eine Sekunde lang in den Ruhezustand zu versetzen, und das Programm druckt nacheinander 2, 3 und 1 aus.

Warum passiert das also? Da das Programm zuerst den Hauptthread ausführt, wird das Programm nach Abschluss der Ausführung des Hauptthreads sofort beendet, sodass keine zusätzliche Zeit für die Ausführung des untergeordneten Threads verbleibt. Wenn Sie den Hauptthread am Ende des Programms 1 Sekunde lang ruhen lassen, hat das Programm genügend Zeit, den untergeordneten Thread auszuführen.

Der Thread endet hier, werfen wir einen Blick auf den Kanal.

Kanal wird auch Kanal genannt. Wie der Name schon sagt, besteht die Funktion des Kanals darin, Daten zwischen mehreren Threads zu übertragen.

Erstelle einen ungepufferten Kanal

chreadandwrite :=make(chan int)

chonlyread := make(<-chan int) //Erstelle einen schreibgeschützten Kanal

chonlywrite := make(chan<- int) // Erstellen Sie einen schreibgeschützten Kanal. Schreibkanal.

Schauen wir uns ein Beispiel an:

import(    "fmt"
    "time"    )funcmain(){    var i = 3    go func(a int) {        fmt.Println(a)
        fmt.Println("1")
    }(i)
    fmt.Println("2")
    time.Sleep(1 * time.Second)}

Bei der Ausführung dieses Codes tritt ein Fehler auf: Schwerwiegender Fehler: Alle Goroutinen schlafen – Deadlock!


Dieser Fehler bedeutet, dass der Thread gefallen ist in einen Deadlock geraten und das Programm kann nicht weiter ausgeführt werden. Was ist also die Ursache für diesen Fehler?

Wir haben einen ungepufferten Kanal erstellt und ihm dann einen Wert zugewiesen. Das Programm geriet nach Abschluss der Zuweisung in einen Deadlock. Da unser Kanal ungepuffert, also synchron, ist, wird das Programm blockiert, bevor der Kanal nach Abschluss der Zuweisung gelesen werden kann. Hier ist ein sehr wichtiges Konzept: Der Kanalmechanismus ist First-In-First-Out. Wenn Sie dem Kanal einen Wert zuweisen, muss dieser gelesen werden, da dies sonst zu einer Blockierung führt. Dies gilt natürlich nur für ungepufferte Kanäle . Bei gepufferten Kanälen blockiert der Sender, bis die Daten in den Puffer kopiert wurden. Wenn der Puffer voll ist, kann der Sender den Blockierungszustand erst wieder aufheben, nachdem der Empfänger die Daten entfernt hat.

Für das obige Beispiel gibt es zwei Lösungen:

1. Fügen Sie dem Kanal einen Puffer hinzu und lassen Sie den Hauptthread am Ende des Programms wie folgt:

    ch :=make(chan int)     
    ch <- 1
      go func() {
        <-ch
        fmt.Println("1")
      }()
      fmt.Println("2")

In diesem Fall In diesem Fall gibt das Programm 1, 2

2 aus. Fügen Sie die Codezeile ch<-1 hinter den Sub-Thread-Code ein. Der Code lautet wie folgt:

    ch :=make(chan int,1)
    ch <- 1
    go func() {
        v := <-ch
        fmt.Println(v)
    }()
    time.Sleep(1 * time.Second)
    fmt.Println("2")

Der Haupt-Thread muss hier nicht ruhen , denn nachdem der Kanal im Hauptthread zugewiesen wurde, wird der Hauptthread blockiert, bis der Wert des Kanals im untergeordneten Thread abgerufen wird.

Schauen wir uns abschließend ein Beispiel für einen Produzenten und einen Konsumenten an:

    ch :=make(chan int)    go func() {
        v := <-ch
        fmt.Println(v)
    }()
    ch <- 1
    fmt.Println("2")

Da der Kanal in diesem Code nicht gepuffert ist, blockiert der Produzenten-Thread, bis der Konsumenten-Thread annimmt, wenn der Produzent dem Kanal einen Wert zuweist die Daten aus dem Kanal aus. Nachdem der Verbraucher die Daten zum ersten Mal entnommen hat, wird der Thread des Verbrauchers auch im nächsten Zyklus blockiert, da der Produzent die Daten noch nicht gespeichert hat. Zu diesem Zeitpunkt führt das Programm den Thread des Produzenten aus. Auf diese Weise wechselt das Programm kontinuierlich zwischen den Consumer- und Producer-Threads, bis die Schleife endet.

Sehen wir uns ein weiteres Beispiel mit Pufferung an:

import (    "fmt"
    "time")func produce(p chan<- int) {    for i := 0; i < 10; i++ {
        p <- i
        fmt.Println("send:", i)
    }
}func consumer(c <-chan int) {    for i := 0; i < 10; i++ {
        v := <-c
        fmt.Println("receive:", v)
    }
}func main() {
    ch := make(chan int)    go produce(ch)    go consumer(ch)
    time.Sleep(1 * time.Second)
}

In diesem Programm kann der Puffer 10 Ganzzahlen vom Typ int speichern, der Thread wird nicht blockiert und es werden 10 Ganzzahlen gleichzeitig gespeichert Die Ganzzahl wird im Kanal gespeichert und beim Lesen auch auf einmal gelesen.

Das obige ist der detaillierte Inhalt vonDetaillierte Erklärung des Golang-Kanals Chan. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

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