Hello, I'm Ganesh. I'm building git-lrc, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. Star Us to help devs discover the project. Do give it a try and share your feedback for improving the product.
In Channels We Go, there are 2 types of channels.
- Buffered channels
- Unbuffered channels
In this article, we will learn about buffered channels.
Buffered channels
Buffered channels are channels that have a buffer size.
How to create a buffered channel?
Which will be defined by the second argument to the makefunction.
This will make the channel able to hold the number of values equal to the buffer size.
package main
import "fmt"
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
fmt.Println(<-ch)
fmt.Println(<-ch)
}
Let's add 2 values to the channel and print them.
Output:
gk@jarvis:~/exp/code/rd/go-exmaple$ go run main.go
1
2
Now let's add 3 values to the channel and print them.
package main
import "fmt"
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
ch <- 3
fmt.Println(<-ch)
fmt.Println(<-ch)
fmt.Println(<-ch)
}
Output:
gk@jarvis:~/exp/code/rd/go-exmaple$ go run main.go
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/home/gk/exp/code/rd/go-exmaple/main.go:9 +0x58
exit status 2
In the error message, we can see that all goroutines are asleep—deadlock!
This is because we are trying to send 3 values to the channel which has a buffer size of 2.
So, the value 3 will be waiting for a receiver to receive it.
But there is no receiver to receive it.
So, the program will deadlock.
Also, we are sending 3 values in the main thread and receiving 3 values in the main thread. So, the program will deadlock.
How to avoid deadlock:
we should send values to the channel in a separate goroutine.
The receiver should be in a separate goroutine.
package main
import "fmt"
func main() {
ch := make(chan int, 2)
// Start a concurrent routine to send the data
go func() {
ch <- 1
ch <- 2
ch <- 3
}()
// Main routine reads the data as it comes in
fmt.Println(<-ch)
fmt.Println(<-ch)
fmt.Println(<-ch)
}
Output:
gk@jarvis:~/exp/code/rd/go-exmaple$ go run main.go
1
2
3
Loop over a channel
We can use the for range loop to iterate over a channel.
package main
import "fmt"
func main() {
ch := make(chan int, 2)
// Start a concurrent routine to send the data
go func() {
ch <- 1
ch <- 2
ch <- 3
}()
// Main routine reads the data as it comes in
for i := range ch {
fmt.Println(i)
}
}
Expected Output:
gk@jarvis:~/exp/code/rd/go-exmaple$ go run main.go
1
2
3
Actual Output:
gk@jarvis:~/exp/code/rd/go-exmaple$ go run main.go
1
2
3
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/home/gk/exp/code/rd/go-exmaple/main.go:16 +0xc5
exit status 2
We expected the output to be 1, 2, 3.
But we got a deadlock.
This is because the for range loop will wait for the channel to be closed.
But we didn't close the channel.
let's close the channel.
package main
import "fmt"
func main() {
ch := make(chan int, 2)
// Start a concurrent routine to send the data
go func() {
ch <- 1
ch <- 2
ch <- 3
close(ch)
}()
// Main routine reads the data as it comes in
for i := range ch {
fmt.Println(i)
}
}
Output:
gk@jarvis:~/exp/code/rd/go-exmaple$ go run main.go
1
2
3
Conclusion
We explored how to work with buffered channels.
Understood how to avoid deadlock in buffered channels.
We also understood how to loop over a channel.
Next we will see how to work with unbuffered channels.
Any feedback or contributors are welcome! It’s online, source-available, and ready for anyone to use.
⭐ Star it on GitHub: https://github.com/HexmosTech/git-lrc

Top comments (0)