Unbuffered Channel in Golang

To create an unbuffered channel, call the function make() without specifying the channel capacity:

var iChan chan int = make(chan int) // channel for data type int
sChan := make(chan string)  // channel for data type string

If the channel is empty, the receiver goroutine is blocked until there is data in the channel. When the sender goroutine sends data, The recipient goroutine receives this data and resumes work.

The sender goroutine can only send data to an empty channel. The sender goroutine is blocked until the data from the channel is received. For example:

package main
import "fmt"
 
func main() {
     
    iChan:= make(chan int) 
     
    go func(){
            fmt.Println("starts")
            iChan<- 2024 // Block until the data is retrieved by the main function
    }()
    fmt.Println(<-iChan) // Retrieving data from channel
    fmt.Println("Done!")
}

Through the unbuffered channel iChan, the goroutine, represented by an anonymous function, transmits the number 2024:

 iChan<- 2024 

The main function gets this number:

fmt.Println(<-iChan)

The general flow of the program looks like this:

  • The main function is launched. It creates a iChan channel and runs the goroutine as an anonymous function.
  • The main function continues to execute and blocks on line fmt.Println(<-iChan) until data is received.
  • The running goroutine runs in parallel as an anonymous function. At the end of its execution, it sends data through the channel: iChan <- 2024. The goroutine blocks until the main function receives data.
  • The main function receives the sent data, and releases and continues its work.

In this case, the goroutine is defined as an anonymous function and therefore it has access to the environment, including the iChan variable. If we work with ordinary functions, then channel objects must be passed through the parameters:

package main

import "fmt"

func main() {
    iChan := make(chan int)

    go printHello(5, iChan) // Start a goroutine

    for i := 0; i < 5; i++ {
        fmt.Println(<-iChan) // Receive data from the channel for each iteration
    }

    fmt.Println("Done")
}

func printHello(n int, ch chan int) {
    for i := 1; i <= n; i++ {
        ch <- i // Sending the current value of i to the channel
        fmt.Println(i, "-", "Hello World")
    }
}

Note how the parameter that represents the data channel of type int: is defined ch chan int. Console output of this program:

1 - Hello World
1
2
2 - Hello World
3 - Hello World
3
4
4 - Hello World
5 - Hello World
5
Done