Channel Blocking
Observant students may have noticed that when we introduced channel declarations and initialization, we did not specify the channel's capacity:
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)
}
But when we demonstrated channel operations, we specified the channel's capacity:
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)
}
For channels without a specified capacity, they are called unbuffered channels, which have no buffer space.
If a sender or receiver is not ready, the first operation will block until the other operation becomes ready.
chan1 := make(chan int) // Unbuffered channel of type int
For channels with a specified capacity and buffer space, they are called buffered channels.
chan2 := make(chan int, 5) // Buffered channel of type int with a capacity of 5
They function like a queue, adhering to the First In First Out (FIFO) rule.
For buffered channels, we can use send operations to append elements to the end of the queue and use receive operations to remove elements from the head of the queue.
What happens if we put more data into a buffered channel than its capacity? Let's check it out. Write the following code into the channel1.go
file:
cd ~/project
touch channel1.go
package main
import "fmt"
func main() {
ch := make(chan int, 1)
ch <- 10
ch <- 20
fmt.Println("succeed")
}
Run the program using the following command:
go run channel1.go
The program output is as follows:
fatal error: all goroutines are asleep - deadlock!
We find that the program deadlocks because the channel is already full.
To solve this problem, we can extract the data from the channel first. Write the following 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")
}
Run the program using the following command:
go run channel.go
The program output is as follows:
Data extracted: 10
succeed
We can continuously use the channel with a limited capacity by adopting a strategy of taking, using, taking, and using again.