An introduction to

In the Go official website, the Channel type is defined as follows.

A channel provides A mechanism for [concurrently executing functions provides] (golang. Google. Cn/ref/spec # Go…). to communicate by sending and receiving values of a specified element type. The value of an uninitialized channel is nil.

Channels provide a mechanism for concurrent execution of functions that communicate by sending and receiving values of specified element types. The value of an uninitialized channel is nil.

“Do not communicate by sharing memory, but share memory by communicating.” This sentence reflects the concept of Go language for concurrent design, and Channel is also an important member of the realization of CSP theory.

Basic operation

Now let’s talk about Channel.

For me, there are two kinds of channels:

  • Unbuffered: Unbuffered in concurrent programming, as in synchronization.
  • Caching: Caching is asynchronous.

The creation of unbuffered channels is similar, but the parameters are different

Talk is cheap, Show Me the Code — Linux founder Linus

Let’s use a simple code to describe the creation and operation of a channel.

Ch1 := make(chan int) // Ch2 := make(chan int, 1) ch2 < -1 ch2 := make(chan int, 1) ch2 < -1Copy the code

We create channels above, including int to specify the type of channel that can be put as.

To understand a channel, we can first think of it as a FIFO queue.

We can think of CH2 as a queue where we can put one element.

What about CH1? Is it a channel that can hold zero elements? Yes, that’s right! So how do you communicate between coroutines via CH1?

Remember we said at the top that there are two kinds of channels, one of which is synchronous? In other words, in order for two coroutines to communicate via CH1, they have to shake hands. When a coroutine puts data into CH1, it must block and wait for another ctrip to pick it up.

The flow of coroutines reading and writing to channels:

  • If the sender writes data to the buffer, the waiting receiver will wake up. Multiple recipients will try to read data from the buffer. If no data is read, the receiver will fall into sleep again.
  • When the receiver reads data from the buffer, the sender will wake up. The sender will try to write data to the buffer. If the buffer is full, the sender will fall into sleep again.

Have encountered the pit

  1. closedchanYou can’t write. You can read
  2. forchannelThe best way to traverse is using range

The source code

The operation of Channel is relatively simple, let’s take a look at the internal implementation of the Go source code. The chan structure is defined in ${GOROOT}/ SRC /runtime/chan.go.

 ​
 type hchan struct {
     qcount   uint           // total data in the queue
     dataqsiz uint           // size of the circular queue
 ​
     buf      unsafe.Pointer // points to an array of dataqsiz elements
     elemsize uint16
     closed   uint32
     elemtype *_type // element type
     sendx    uint   // send index
     recvx    uint   // receive index
     recvq    waitq  // list of recv waiters
     sendq    waitq  // list of send waiters
 ​
     // lock protects all fields in hchan, as well as several
     // fields in sudogs blocked on this channel.
     //
     // Do not change another G's status while holding this lock
     // (in particular, do not ready a G), as this can deadlock
     // with stack shrinking.
     lock mutex
 }
 ​
Copy the code
  • qcount– Number of elements in Channel;
  • dataqsiz– The length of the loop queue in a Channel;
  • buf– Buffer data pointer to Channel;
  • sendx– The location to which the sending operation of a Channel is processed;
  • recvx– The position to which the receive operation of a Channel is processed;

Using the structure above, we can abstract the following picture:

summary

Channel is a new member of concurrency control. Although it has internal locks, it is insensitive to us. In the official network library, Go uses many channels for concurrency control.

I’ll write it here and share it later.