Kanalblockierung (Channel Blocking)
Aufmerksame Schülerinnen und Schüler haben vielleicht bemerkt, dass wir bei der Einführung der Kanaldeklaration (Channel Declaration) und -initialisierung (Channel Initialization) die Kapazität des Kanals (Channel) nicht angegeben haben:
package main
import "fmt"
func main() {
// Stores integer data in the channel
ch1 := make(chan int) // Same below
// Stores boolean data in the channel
ch2 := make(chan bool)
// Stores []int data in the channel
ch3 := make(chan []int)
fmt.Println(ch1, ch2, ch3)
}
Aber als wir die Kanaloperationen (Channel Operations) demonstrierten, haben wir die Kapazität des Kanals (Channel) angegeben:
package main
import "fmt"
func main() {
// Specify the channel capacity as 3
ch := make(chan int, 3)
ch <- 10
ch <- 20
fmt.Println(<-ch)
fmt.Println(<-ch)
}
Für Kanäle (Channels), deren Kapazität nicht angegeben ist, werden sie als ungebufferte Kanäle (unbuffered channels) bezeichnet, die keinen Pufferplatz haben.
Wenn ein Sender oder Empfänger nicht bereit ist, blockiert die erste Operation, bis die andere Operation bereit ist.
chan1 := make(chan int) // Unbuffered channel of type int
Für Kanäle (Channels), deren Kapazität und Pufferplatz angegeben sind, werden sie als gepufferte Kanäle (buffered channels) bezeichnet.
chan2 := make(chan int, 5) // Buffered channel of type int with a capacity of 5
Sie funktionieren wie eine Warteschlange und folgen der First-In-First-Out (FIFO)-Regel.
Bei gepufferten Kanälen (buffered channels) können wir Sendevorgänge verwenden, um Elemente an das Ende der Warteschlange anzufügen, und Empfangsvorgänge verwenden, um Elemente vom Anfang der Warteschlange zu entfernen.
Was passiert, wenn wir mehr Daten in einen gepufferten Kanal (buffered channel) legen, als seine Kapazität beträgt? Lassen Sie uns es überprüfen. Schreiben Sie folgenden Code in die Datei channel1.go
:
cd ~/project
touch channel1.go
package main
import "fmt"
func main() {
ch := make(chan int, 1)
ch <- 10
ch <- 20
fmt.Println("succeed")
}
Führen Sie das Programm mit dem folgenden Befehl aus:
go run channel1.go
Die Ausgabe des Programms ist wie folgt:
fatal error: all goroutines are asleep - deadlock!
Wir stellen fest, dass das Programm in einem Deadlock endet, weil der Kanal bereits voll ist.
Um dieses Problem zu lösen, können wir zuerst die Daten aus dem Kanal extrahieren. Schreiben Sie folgenden Code in channel.go
:
package main
import "fmt"
func main() {
ch := make(chan int, 1)
ch <- 10
fmt.Println("Data extracted:", <-ch)
ch <- 20
fmt.Println("succeed")
}
Führen Sie das Programm mit dem folgenden Befehl aus:
go run channel.go
Die Ausgabe des Programms ist wie folgt:
Data extracted: 10
succeed
Wir können den Kanal mit begrenzter Kapazität kontinuierlich nutzen, indem wir eine Strategie von Entnehmen, Verwenden, Entnehmen und Wiederverwenden anwenden.