Learn Go: Buffered Channels in Golang #30

Buffered channels work similar to unbuffered channels, but we can send multiple pieces of data to the channel

Gopher

Lets go!!

Published · Feb 9

Previous Tutorial: Introduction to Channels in Golang #29

All the channels we discussed in the previous tutorial were basically unbuffered. As we discussed in the channels tutorial in detail, sends and receives to an unbuffered channel are blocking.
. . .

What are buffered channels?

It is possible to create a channel with a buffer. Sends to a buffered channel are blocked only when the buffer is full. Similarly receives from a buffered channel are blocked only when the buffer is empty.

In our mining example, we could run into a situation where our finding gopher can find 3 pieces of ore in the time it takes the breaking gopher to process one piece of ore.

In order to not let the surveying gopher spend most of its time waiting to send the breaking gopher some ore until it finishes, we can use a buffered channel. Lets start by making a buffered channel with a capacity of 3.
bufferedChan := make(chan string, 3)

Buffered channels work similar to unbuffered channels, but with one catch — we can send multiple pieces of data to the channel before needing another go routine to read from it.

Buffered channels work similar to unbuffered channels, but with one catch — we can send multiple pieces of data to the channel before needing another go routine to read from it.

package main

import (
"fmt"
"time"
)

func main() {

bufferedChan := make(chan string, 3)

go func() {
bufferedChan <- "first"
fmt.Println("Sent 1st")
bufferedChan <- "second"
fmt.Println("Sent 2nd")
bufferedChan <- "third"
fmt.Println("Sent 3rd")
}()

<-time.After(time.Second * 1)

go func() {
firstRead := <-bufferedChan
fmt.Println("Receiving..")
fmt.Println(firstRead)
secondRead := <-bufferedChan
fmt.Println(secondRead)
thirdRead := <-bufferedChan
fmt.Println(thirdRead)
}()

<-time.After(time.Second * 3)
}


The order of printing between our two go routines would be:
Sent 1st Sent 2nd Sent 3rd Receiving.. first second third

To keep things simple, we won’t be using buffered channels in our final program, but it’s important to know what types of channels are available in your concurrency tool belt.
Note: Using buffered channels doesn’t prevent blocking from happening. For example, if the finding gopher is 10 times faster than the breaker, and they communicate through a buffered channel of size 2, the finding gopher will still block multiple times in the program.
. . .

Length vs Capacity

The capacity of a buffered channel is the number of values that the channel can hold. This is the value we specify when creating the buffered channel using the make function.

In the program above, the channel is created with a capacity of 3, that is, it can hold 3 strings.

We then write 2 strings to the channel in line nos. 9 and 10 respectively. Now the channel has 2 strings queued in it and hence its length is 2.
package main

import (
"fmt"
)

func main() {

bufferedChan := make(chan string, 3)

bufferedChan <- "first"
fmt.Println("Sent 1st")
fmt.Println("len -> ", len(bufferedChan), "capacity ->", cap(bufferedChan))
bufferedChan <- "second"
fmt.Println("Sent 2nd")
fmt.Println("len -> ", len(bufferedChan), "capacity ->", cap(bufferedChan))
}


In line no. 11, we add a string to the channel. Now the channel has only one string queued in it and hence its length becomes 1. This program will print,
Sent 1st len -> 1 capacity -> 3 Sent 2nd len -> 2 capacity -> 3

. . .

Conclusion

We discovered the differences between both buffered and unbuffered channels and how we could use them to our advantage within our concurrent go programs.
. . .

. . .

Never miss a post from Gopher , when you sign up for Ednsquare.