In Golang, channel provides a mechanism to communicate between different goroutines. This tutorial gives you some highlights when working with channel
Create a new channel
You have to create a new channel before using it with the make
function (same as with slice
and map
)
c := make(chan Type)
Channels behave like pointers
The created channel acts as a reference to the underlying data structure, so it's unnecessary to use a pointer to channel
Send and receive messages with channel
You can use channel
to send and receive messages of the same type between goroutines
Let's take a look at the following example
Output
hello, channel!
In the above program
- We created a string channel before using with
make
c := make(chan string)
- You can use
<-
operator to send and receive messages from the channel. We sent "hello, channel!" to channelc
inside a new goroutine
c <- "hello, channel!"
- And received messages from
c
in the main goroutine
s := <- c
Channel types
There're 3 types of channel based on the channel direction operator <-
chan T
is a bidirectional channel, can send and received messages of typeT
chan <- string
is a receive channel, can only receive messages of typestring
chan -> int
is a send channel, can only send messages of typeint
Unbuffered vs buffered channel
Channels are unbuffered and block by default
When you allocate a new channel with the make function
c := make(chan string)
The created channel c
is unbuffered and block / synchronous sends and receives block until the other side is ready
package main
import (
"fmt"
)
func main() {
uc := make(chan string)
uc <- "hello, unbuffered channel!"
s := <- uc
fmt.Println(s)
}
Output
fatal error: all goroutines are asleep - deadlock!
The program throws a panic as uc <- "hello, channel!"
blocks the main goroutine because of no receives is ready
Buffered channels only block when full
You can provide an optional integer argument to indicate the buffered size when creating a new channel with make
c := make(chan string, 2)
Sends to a buffered channel block when the buffer is full
package main
import (
"fmt"
)
func main() {
bc := make(chan string, 2)
bc <- "hello, buffered channel!"
bc <- "may i send more?"
s1 := <- bc
s2 := <- bc
fmt.Println(s1)
fmt.Println(s2)
}
Output
hello, buffered channel!
may I send more?
Try to modify the above program to send more than 2 messages to the buffered channel then comparing the outputs
Close a channel
You can close a bidirectional or send-only channel c
by using the built-in function close(c)
Only the sender should close a channel to indicate that no more values will be sent
You can still receive messages from a closed channel. After calling close, and after any previously sent values have been received, receive operations will return the zero value for the channel's type without blocking.
Usually, you don't have to close a channel except when you want to use it as an ending signal