DEV Community

Cover image for Go Course: Channels
Karan Pratap Singh
Karan Pratap Singh

Posted on • Originally published at karanpratapsingh.com

Go Course: Channels

In this lesson, we will learn about Channels.

So what are channels?

Well, simply defined a channel is a communications pipe between goroutines. Things go in one end and come out another in the same order until the channel is closed.

channel

As we learned earlier, channels in Go are based on Communicating Sequential Processes (CSP).

Creating a channel

Now that we understand what channels are, let's see how we can declare them.

var ch chan T
Enter fullscreen mode Exit fullscreen mode

Here, we prefix our type T which is the data type of the value we want to send and receive with the keyword chan which stands for a channel.

Let's try printing the value of our channel c of type string.

func main() {
    var ch chan string

    fmt.Println(c)
}
Enter fullscreen mode Exit fullscreen mode
$ go run main.go
<nil>
Enter fullscreen mode Exit fullscreen mode

As we can see, the zero value of a channel is nil and if we try to send data over the channel our program will panic.

So, similar to slices we can initialize our channel using the built-in make function.

func main() {
    ch := make(chan string)

    fmt.Println(c)
}
Enter fullscreen mode Exit fullscreen mode

And if we run this, we can see our channel was initialized.

$ go run main.go
0x1400010e060
Enter fullscreen mode Exit fullscreen mode

Sending and Receiving data

Now that we have a basic understanding of channels, let us implement our earlier example using channels to learn how we can use them to communicate between our goroutines.

package main

import "fmt"

func speak(arg string, ch chan string) {
    ch <- arg // Send
}

func main() {
    ch := make(chan string)

    go speak("Hello World", ch)

    data := <-ch // Receive
    fmt.Println(data)
}
Enter fullscreen mode Exit fullscreen mode

Notice how we can send data using the channel<-data and receive data using the data := <-channel syntax.

And if we run this

$ go run main.go
Hello World
Enter fullscreen mode Exit fullscreen mode

Perfect, our program ran as we expected.

Buffered Channels

We also have buffered channels that accept a limited number of values without a corresponding receiver for those values.

buffered-channel

This buffer length or capacity can be specified using the second argument to the make function.

func main() {
    ch := make(chan string, 2)

    go speak("Hello World", ch)
    go speak("Hi again", ch)

    data1 := <-ch
    fmt.Println(data1)

    data2 := <-ch
    fmt.Println(data2)
}
Enter fullscreen mode Exit fullscreen mode

Because this channel is buffered, we can send these values into the channel without a corresponding concurrent receive. This means sends to a buffered channel block only when the buffer is full and receives block when the buffer is empty.

By default, a channel is unbuffered and has a capacity of 0, hence, we omit the second argument to the make function.

Next, we have directional channels.

Directional channels

When using channels as function parameters, we can specify if a channel is meant to only send or receive values. This increases the type-safety of our program as by default a channel can both send and receive values.

directional-channels

In our example, we can update our speak function's second argument such that it can only send a value.

func speak(arg string, ch chan<- string) {
    ch <- arg // Send Only
}
Enter fullscreen mode Exit fullscreen mode

Here, chan<- can only be used for sending values and will panic if we try to receive values.

Closing channels

Also, just like any other resource, once we're done with our channel, we need to close it. This can be achieved using the built-in close function.

Here, we can just pass our channel to the close function.

func main() {
    ch := make(chan string, 2)

    go speak("Hello World", ch)
    go speak("Hi again", ch)

    data1 := <-ch
    fmt.Println(data1)

    data2 := <-ch
    fmt.Println(data2)

    close(ch)
}
Enter fullscreen mode Exit fullscreen mode

Optionally, receivers can test whether a channel has been closed by assigning a second parameter to the receive expression.

func main() {
    ch := make(chan string, 2)

    go speak("Hello World", ch)
    go speak("Hi again", ch)

    data1 := <-ch
    fmt.Println(data1)

    data2, ok := <-ch
    fmt.Println(data2, ok)

    close(ch)
}
Enter fullscreen mode Exit fullscreen mode

if ok is false then there are no more values to receive and the channel is closed.

In a way, this is similar to how we check if a key exists or not in a map.

Properties

Lastly, let's discuss some properties of channels:

  • A send to a nil channel blocks forever.
var c chan string
c <- "Hello, World!" // Panic: all goroutines are asleep - deadlock!
Enter fullscreen mode Exit fullscreen mode
  • A receive from a nil channel blocks forever.
var c chan string
fmt.Println(<-c) // Panic: all goroutines are asleep - deadlock!
Enter fullscreen mode Exit fullscreen mode
  • A send to a closed channel panics.
var c = make(chan string, 1)
c <- "Hello, World!"
close(c)
c <- "Hello, Panic!" // Panic: send on closed channel
Enter fullscreen mode Exit fullscreen mode
  • A receive from a closed channel returns the zero value immediately.
var c = make(chan int, 2)
c <- 5
c <- 4
close(c)
for i := 0; i < 4; i++ {
    fmt.Printf("%d ", <-c) // Output: 5 4 0 0
}
Enter fullscreen mode Exit fullscreen mode
  • Range over channels.

We can also use for and range to iterate over values received from a channel.

package main

import "fmt"

func main() {
    ch := make(chan string, 2)

    ch <- "Hello"
    ch <- "World"

    close(ch)

    for data := range ch {
        fmt.Println(data)
    }
}
Enter fullscreen mode Exit fullscreen mode

This article is part of my open source Go Course available on Github.

GitHub logo karanpratapsingh / learn-go

Master the fundamentals and advanced features of the Go programming language

Learn Go

Hey, welcome to the course, and thanks for learning Go. I hope this course provides a great learning experience.

This course is also available on my website and as an ebook on leanpub. Please leave a ⭐ as motivation if this was helpful!

Table of contents

What is Go?

Go (also known as Golang) is a programming language developed at Google in 2007 and open-sourced in 2009.

It focuses on simplicity, reliability, and efficiency. It was designed to combine the efficacy, speed…

Top comments (0)