Regular channels

To declare a channel in Go, you simply use the make keyword, as follows:

myChannel := make(chan int)

In the preceding code, we created and initialized a channel called myChannel that can hold int values. This channel can then be used to send an int value from one goroutine to another.

Here is how to receive a value from a channel:

//myIntValue will host the value received from the channel
myIntValue := <-myChannel

Here is how to send a value to a channel:

myChannel <- 4

 

Whenever you execute a send or a receive operation on a regular Go channel, your goroutine will block until the value is fully sent or received. This simply means that if you send a value via a channel but there is no other goroutine waiting for it on the other end, your goroutine will block. On the other hand, if you are attempting to receive a value via a channel but there is no other goroutine sending it on the other end, your goroutine will block. This behavior ensures that your code is synchronized, your values are fresh and up to date, and avoids the numerous problems that you can typically face in other programming languages when you use locks.

Let's take a look at a complete program showcasing two goroutines communicating, in order to learn more about Go channels:

package main

import (
"fmt"
"time"
)

func runLoopSend(n int, ch chan int) {
for i := 0; i < n; i++ {
ch <- i
}
close(ch)
}

func runLoopReceive(ch chan int) {
for {
i, ok := <-ch
if !ok {
break
}
fmt.Println("Received value:", i)
}
}

func main() {
myChannel := make(chan int)
go runLoopSend(10, myChannel)
go runLoopReceive(myChannel)
time.Sleep(2 * time.Second)
}

In the preceding code, we created a channel called myChannel, which we then pass to two goroutines: runLoopSend() and runLoopReceive(). The runLoopSend() function will keep sending values to this channel, whereas the runLoopReceive() function will keep receiving values from this channel.

The preceding code will provide the following output:

Received value: 0
Received value: 1
Received value: 2
Received value: 3
Received value: 4
Received value: 5
Received value: 6
Received value: 7
Received value: 8
Received value: 9

Let's first focus on runLoopSend() because there is a new concept that we are showcasing here. Take a look at the following code line:

close(ch)

This syntax can be used to close a channel. Once a channel is closed, you cannot send data to it anymore, otherwise, a panic will occur.

Now, let's take a look at runLoopReceive, particularly at this following line:

i, ok := <-ch

The preceding line is a special syntax to inspect whether a channel is closed. If the channel is not closed, the value of ok will be true, while i will get the value getting sent via the channel. On the other hand, if the channel is closed, ok will be false. In the runLoopReceive goroutine, we break out of the for loop if ok is false.

There is actually another, more elegant way to write this for loop:

  for {
i, ok := <-ch
if !ok {
break
}
fmt.Println("Received value:", i)
}

 

We can replace the preceding code with the following code:

  for i := range ch {
fmt.Println("Received value:", i)
}

The for..range syntax is allowed on channels as it allows you to keep receiving data from a channel until the channel gets closed. 

The output of the program will simply be as follows:

Received value: 0
Received value: 1
Received value: 2
Received value: 3
Received value: 4
Received value: 5
Received value: 6
Received value: 7
Received value: 8
Received value: 9
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.20.224.107