Open In App

Buffered Channel in Golang

Channels can be defined as pipes used for Goroutines to communicate. Similar to how water flows from one end to another in a pipe, data can be sent from one end and received from the another end using channels. By default channels are unbuffered, which states that they will only accept sends (chan <-) if there is a corresponding receive (<- chan) which are ready to receive the sent value. Buffered channels allows to accept a limited number of values without a corresponding receiver for those values. It is possible to create a channel with a buffer. Buffered channel are blocked only when the buffer is full. Similarly receiving from a buffered channel are blocked only when the buffer will be empty.

Buffered channels can be created by passing an additional capacity parameter to the make( ) function which specifies the size of the buffer.



Syntax :

ch := make(chan type, capacity)           // chan defines channel type 



Here , capacity in the above syntax should be greater than 0 for a channel to have a buffer. The capacity for an unbuffered channel is 0 by default and hence it omit the capacity parameter.

Example 1 : Code to create a buffered channel.




package main
 
import (
    "fmt"
)
 
func main() {
 
    // create a buffered channel
    // with a capacity of 2.
    ch := make(chan string, 2)
    ch <- "geeksforgeeks"
    ch <- "geeksforgeeks world"
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}

Output:

geeksforgeeks
geeksforgeeks world

Here in above code ,it is possible to write 2 strings into the channel without being blocked. It take 2 strings to the channel  and does not block and print the result.

Example 2 :  Program that writes to a buffered channel blocks.




package main
 
import (
    "fmt"
    "time"
)
 
func write(ch chan int) {
    for i := 0; i < 4; i++ {
        ch <- i
        fmt.Println("successfully wrote", i, "to ch")
    }
    close(ch)
}
func main() {
 
    // creates capacity of 2
    ch := make(chan int, 2)
    go write(ch)
    time.Sleep(2 * time.Second)
    for v := range ch {
        fmt.Println("read value", v, "from ch")
        time.Sleep(2 * time.Second)
 
    }
}

Output: 

successfully wrote 0 to ch
successfully wrote 1 to ch
read value 0 from ch
successfully wrote 2 to ch
read value 1 from ch
successfully wrote 3 to ch
read value 2 from ch
read value 3 from ch

Here in above code the write Goroutine has a for loop which writes numbers from 0 to 3 to the ch channel. The capacity of this buffered channel is 2 and hence the write Goroutine will be able to write values 0 and 1 to the ch channel immediately and then it blocks until at least one value is read from ch channel as defined below :-

successfully wrote 0 to ch
successfully wrote 1 to ch

After that, the read value and then sleeps for 2 seconds again and this cycle continues until the ch is closed. So the program will print the following lines after 2 seconds, as :-

read value 0 from ch  
successfully wrote 2 to ch 

And this will continue until all values are written to the channel and it is closed in the write Goroutine.

Deadlocks in Buffered Golang Channel

It is defined as situation where the program during execution  will result in fatal error due to panic at run time.

Example :




package main
 
import (
    "fmt"
)
 
func main() {
    ch := make(chan string, 2)
    ch <- "geeksforgeeks"
    ch <- "hello"
    ch <- "geeks"
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}

Here , in above code the write is blocked since the channel has exceeded its capacity and program reaches deadlock situation and print following message :

fatal error: all goroutines are asleep - deadlock!



goroutine 1 [chan send]:

main.main()

    /tmp/sandbox048494311/prog.go:11 +0x8d

Article Tags :