DEV Community

Cover image for How to work with buffered channels?
Ganesh Kumar
Ganesh Kumar

Posted on

How to work with buffered channels?

#go

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.

  1. Buffered channels
  2. 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)
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

Output:

gk@jarvis:~/exp/code/rd/go-exmaple$ go run main.go 
1
2
3
Enter fullscreen mode Exit fullscreen mode

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)
    }
}
Enter fullscreen mode Exit fullscreen mode

Expected Output:

gk@jarvis:~/exp/code/rd/go-exmaple$ go run main.go 
1
2
3
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

gk@jarvis:~/exp/code/rd/go-exmaple$ go run main.go 
1
2
3
Enter fullscreen mode Exit fullscreen mode

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.

git-lrc

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)