Channels

Like a river flows, surely to the sea

2-minute read
Made by ChickenFryBytes Studios
Table of Contents

We can use channels in order to send information among concurrent goroutines. They can be thought of as pipes in which we pass data around. A new channel is created using the syntax:


make(chan <dataType>)
// e.g. a channel for passing strings
myChannel := make(chan string)

We can then send values through the channel using the syntax:


myChannel <- "this is my message to you"

Receiving values from a channel

In order to get a value in a channel, we use the syntax:


// store value from channel into variable myMessage
myMessage := <-myChannel

Consider the following code:

package main

import "fmt"

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

	myMessages := []string{
		"Lester is ok",
		"Nana is at least 60 now",
	}

	for _, message := range myMessages {
		go func() {
			littleBirdie <- message
		}()
	}

	// get first message
	message := <-littleBirdie
	// print first message
	fmt.Println(message)

	// print second message
	fmt.Println(<-littleBirdie)
}
channels.go
Copy

Channels are unbuffered

Channels are, by default, unbuffered meaning they only accept sends (chan <-) once there is a corresponding receive (<- chan) in the code. A deadlock occurs when there is a send and receive operation in the same goroutine:

package main

import "fmt"

func main() {
	bits := make(chan int)
	bits <- 1

	fmt.Println("Sent a bit of 1")
	fmt.Println("Received", <-bits)
}
channels-deadlock.go
Copy

Deadlocks can also occur if the receive operations exceed the number of values passed into the channel:

package main

import "fmt"

func main() {
	bits := make(chan int)
	go func() {
		bits <- 1
		bits <- 0
	}()

	fmt.Println("Sent a bit of 1")
	fmt.Println("Received", <-bits)
	fmt.Println("Received", <-bits)

	// asking for too many values
	fmt.Println("Received", <-bits)
}
channels-deadlock-2.go
Copy

Channel buffering

Channel synchronization

Channel directions


Support us via BuyMeACoffee