Today is the 14th article on Golang, and you can review it by clicking on the album above.

Today we’ll take a look at another very important concept in Golang — channels. One of the questions we asked when we introduced Goroutines was, how do we keep goroutines talking to each other when we start multiple Goroutines?

To answer that question, we need channels.

channel

The English word for channel is channel, and the key word in golang is chan. It’s used to transfer data between goroutines, so you might ask, why does it have to be between Goroutines, not between functions?

Because normal transmission data is passed directly as parameters, only in concurrent scenarios, where multiple threads are isolated from each other, a special structure is required to transmit data.

Chan may seem strange and almost never appears in any other language, but its principles and use are simple.

Let’s look at how it’s used, first defining a chan, or as usual, using the make keyword. As we mentioned earlier, one of golang’s design principles is to save when you can, and keep things simple when you can. As you can see from the make keyword, it can create everything from a slice to a map to a channel.

So when we want to create a chan, we can do it with make.

Ch := make(chan int)

Copy the code

We have the following type after chan, which represents the data type that this channel transmits. If you want to transmit any type, you can use the interface{} we talked about earlier.

When Chan created it, it was very easy to get data from it or put data into it. There was no API, just a visual transfer statement.

So let’s say we now have a chan which is ch, and we want to put data in, we can do ch < -a. We want to get data from ch, we can get v := < -ch.

We use arrows to show the flow of data, isn’t that visually intuitive?

blocking

But that’s not all. One of the key things about chan is that its use is blocked. So the downstream takes one piece of data from the chan so we can pass in one piece of data. Otherwise, the code that transfers the data will wait for Chan to clear it.

Similarly, if we define a statement to read data from the chan, if the current chan is empty, it will block until there is data in the chan.

So we know that there needs to be a producer as well as a consumer in the chan usage scenario. Let’s take a look at an example from golang:

package main



import "fmt"



func sum(s []int, c chan int) {

 sum := 0

 for _, v := range s {

  sum += v

 }

 c <- sum // Send and into c

}



func main(a) {

 s := []int{7.2.8.9 -.4.0}



 c := make(chan int)

 go sum(s[:len(s)/2], c)

 go sum(s[len(s)/2:], c)

 x, y := <-c, <-c // Receive from c



 fmt.Println(x, y, x+y)

}

Copy the code

We started two Goroutines to sum and return the array. The data produced by the Goroutine cannot be returned directly, so it can only be transmitted through chan. Chan transmission requires downstream consumption, so the data from the above two goroutines will be transmitted to x, y: <-c, <-c.

As mentioned earlier, chan’s transfer is blocked, so this statement will wait until both goroutines are evaluated.

If you are confused and feel as if you understand something and as if you don’t, a simple solution is to make a change to the situation while you understand it. Think of the chan usage scenario as the producer-consumer design pattern we introduced earlier, where chan’s role is actually the queue.

The producer sends data to the queue and the consumer consumes it. The only difference is that the size of the queue is 1, and data cannot be transmitted until both the producer and the consumer are ready.

Chan’s buffer

As mentioned above, chan has a capacity of 1 and can only transfer data when both the consumer and production sides are ready. We can also add buffering to chan. If the consumer side is too late to consume all the data, the production side is allowed to temporarily store the data in chan without blocking until chan is full.

The usage is also very simple. When we create chan from make, we can add an extra parameter to indicate the capacity, similar to the way we created slices before.

Ch := make(chan int.100)

Copy the code

For example, we create a channel with a buffer of 100.

But by the way, this doesn’t happen very often, and the reason is simple. Because the consumption situation of upstream and downstream is unified, if the producer’s production speed is too fast, and the consumer can’t keep up, even if it is temporarily stored in the buffer, it is no use, sooner or later, it will still be blocked.

close

When we are done with the channel, we can close it with the close statement.

The Close operation can only be performed on the production side. If the channel is closed on the consumer side, a panic will occur. When we receive data from Chan, we can add a parameter to determine whether the channel is closed.

v, ok := <- ch

if! ok {

 return

}

Copy the code

So we can tell when Chan shut down.

This is the end of today’s article, if you like this article, please invite a wave of quality sanlian, give me a little support (follow, forward, like).

reading

Python | a frequent visitor to the interview, the classic mode of production of consumers

Original link, ask a concern

– END –

🏆 technology project phase ii | and I Go those things…