Buffered vs Unbuffered Channel in Golang

tech · Jan 24, 2021 · ~4 min
Photo by @quinoal on Unsplash
Photo by @quinoal on Unsplash

Small talk about channel

If we talk about concurrency in Golang, Golang provides us with a type of concurrency communication called Channel. Channel itself helps us to communicate between goroutines. We can send and receive messages from one goroutine to another. There are two types of channel in golang that we can used and let’s talk about them.

Unbuffered Channel

Unbuffered channel is a channel that initially has no capacity to store message inside it. Unbuffered channel requires us to fill the message in order to make the goroutine process unblocked by the channel. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main

import (
  "fmt"
  "time"
)

func access(ch chan int) {
  time.Sleep(time.Second)
  fmt.Println("start accessing channel\n")

  for i := range ch {
    fmt.Println(i)
    time.Sleep(time.Second)
  }
}

func main() {
  ch := make(chan int)
  defer close(ch)

  go access(ch)

  for i := 0; i < 9; i++ {
    ch <- i
    fmt.Println("Filled")
  }

  time.Sleep(3 * time.Second)
}

In the example above, our main function blocked when filling ch one by one. And our access function will print the message filled by main function one by one also because of the for loop.

Here is the output of the example above:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
$ go run chan.go 
start accessing channel

0
Filled
1
Filled
2
Filled
3
Filled
4
Filled
5
Filled
6
Filled
7
Filled
8
Filled

Buffered Channel

Unlike the Unbuffered Channel, Buffered Channel has a capacity to store messages inside it. Buffered Channel could be filled up to its defined capacity, not only one message. For example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import (
  "fmt"
  "time"
)

func access(ch chan int) {
  time.Sleep(time.Second)
  fmt.Println("start accessing channel\n")

  for i := range ch {
    fmt.Println(i)
    time.Sleep(time.Second)
  }
}

func main() {
  // only modify this line to defined the capacity
  ch := make(chan int, 3)
  defer close(ch)

  go access(ch)

  for i := 0; i < 9; i++ {
    ch <- i
    fmt.Println("Filled")
  }

  time.Sleep(3 * time.Second)
}

Here is the output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
$ go run chan.go
Filled
Filled
Filled
start accessing channel

0
Filled
1
Filled
2
Filled
3
Filled
4
Filled
5
Filled
6
7
8

As you can see, the ch could be filled first until it is full-capacity then the other goroutine could access it one by one.

Differences

Unbuffered Channel has no capacity initially, but Buffered Channel has a capacity.

Unbuffered Channel will block the goroutine whenever it is empty and waiting to be filled. But Buffered Channel will also block the goroutine either when it is empty and waiting to be filled or it's on its full-capacity and there's a statement that want to fill the channel.

Capacity

1
2
3
unbuffered := make(chan int)

buffered := make(chan int, 30)

Empty and Waiting to be filled

Both Buffered and Unbuffered channel blocks the goroutine until it is filled in this case blocks for a second.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
func main() {
  ch := make(chan int)
  defer close(ch)

  go func(ch chan int) {
    time.Sleep(time.Second)
    ch <- 1
  }(ch)

  <-ch
}

Full Capacity and there’s statement that want to fill the channel

Only Buffered channel blocks on ch <- 2 because the ch is on its full capacity and waiting to be released. The Unbuffered Channel will go deadlock this time because there’s no goroutine accessing the message 2 but it is filled.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func main() {
  ch := make(chan int, 1)
  defer close(ch)

  go func(ch chan int) {
    time.Sleep(time.Second)
    <-ch
  }(ch)

  ch <- 1
  ch <- 2
}

Thank you for reading!

· · ·

Love This Content?

Any kind of supports is greatly appreciated! Kindly support me via Bitcoin, Ko-fi, Trakteer, or just continue to read another content. You can write a response via Webmention and let me know the URL via Telegraph.