Technology Sharing

Go language --- concurrent programming channel (dual channel, single channel) and application examples (producer consumer, printer model)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Channel

Goroutines run in the same address space, so access to shared memory must be synchronized.Goroutines communicate to share memory, rather than sharing memory to communicate.

The reference type channel is a specific implementation of the CSP mode and is used for multiple goroutine communications. It implements synchronization internally to ensure concurrency safety.

Channel Type

Similar to a map, a channel is also a reference to the underlying data structure created by make.
When we copy a channel or use it as a function parameter, we just copy a channel reference, so the caller and the callee will reference the same channel object. Like other reference types, the zero value of the channel is nil.
When defining a channel, you also need to define the type of values ​​that will be sent to the channel. Channels can be created using the built-in make() function:

make (chan Type)
make (chan Type,capacity)
  • 1
  • 2
  • When capacity=0, the channel is unbuffered and blocking reading and writing. When capacity>0, the channel is cached and non-blocking, and writing is blocked only when capacity elements are filled.
  • Chamnel receives and sends data through the operator <-. The syntax for sending and receiving data is:
channel<-value   //发送value 到channel
<-channel     //接收并将其丢弃
x:=<-channel   //从 channel 中接收数据,并賦偵给x
x,ok:=<-channel   //功能同上,同时检查通道是否已关闭或者是否为空
  • 1
  • 2
  • 3
  • 4

By default, channel sends and receives are blocked unless the other end is ready, which makes goroutine synchronization much simpler without explicit locks.

accomplish

insert image description here

  • The pipes are placed one in front of the print and one behind the print.
  • If Person2 is executed first, there is no data in the pipeline, and it will be blocked.
  • After Person1 executes and prints the data, it inputs data into the pipeline, and Person2 will sense it and start printing.

Synchronization and data interaction through channels

insert image description here
insert image description here

Unbuffered channels

An unbuffered channel is a channel that has no ability to store any value before receiving it.
This type of channel requires that the sending goroutine and the receiving goroutine are ready at the same time to complete the sending and receiving operations. If the two goroutines are not ready at the same time, the channel will cause the goroutine that performs the sending or receiving operation first to block and wait.
This interactive behavior of sending and receiving on the channel is inherently synchronous. Neither operation can exist independently of the other.
The following diagram shows how two goroutines can share a value using unbuffered channels:
insert image description here

  • That is, the channel itself cannot store anything, one puts something and the other takes it immediately.
  • In step 1, both goroutines reach the channel, but neither starts performing a send or receive.
  • In step 2, the goroutine on the left reaches into the channel, simulating the act of sending data to the channel. At this point, the goroutine is locked in the channel until the exchange is complete.
  • In step 3, the right goroutine puts its hand into the channel, which simulates receiving data from the channel. This goroutine will also be locked in the channel until the exchange is completed.
  • In steps 4 and 5, the swap happens, and finally, in step 6, both goroutines take their hands out of the channel, which simulates the locked goroutine getting released. Both goroutines can now do other things.

Create an unbuffered channel

make (chan Type)//等价于make (chan Type,0)
  • 1

If no buffer capacity is specified then the channel is synchronous and will therefore block until the sender is ready to send and the receiver is ready to receive.

insert image description here

  • ch&lt;-i writes data to the channel, and the main coroutine will execute it only after it senses it. At this time, the sub-coroutine will also block and wait. The sub-coroutine will continue only after the pipeline has read all the data.
  • However, println prints data after reading the pipe, so the printing speed is determined by the system.

Buffered channels

A buffered channel is a channel that can store one or more values ​​before receiving them.
This type of channel does not require that the goroutines must complete sending and receiving at the same time. The conditions under which the channel blocks sending and receiving actions are also different. Receiving actions will only block if there are no values ​​to receive in the channel. Sending actions will only block if the channel has no available buffer to accommodate the value to be sent.
This leads to a big difference between buffered and unbuffered channels: unbuffered channels guarantee that the sending and receiving goroutines will exchange data at the same time: buffered channels have no such guarantee.
insert image description here

  • In step 1, the goroutine on the right is receiving a value from the channel.
  • In step 2, the goroutine on the right has completed the action of receiving a value independently, while the goroutine on the left is sending a new value to the channel.
  • In step 3, the left goroutine is still sending a new value to the channel, while the right goroutine is receiving another value from the channel. The two operations in this step are neither synchronized nor block each other.
  • Finally, in step 4, all sends and receives are complete, and the channel still has several values ​​in it, with some space for more.

create

make (chan Type,capacity)
  • 1

If a buffer capacity is given, the channel is asynchronous and communication proceeds without blocking as long as the buffer has free space to send data or contains data that can be received.

accomplish

insert image description here

  • If there are enough data stored, it will block and wait for reading. When the main coroutine has read a data and there is a free position, the sub-coroutine will continue to execute, and the subsequent printing order is uncertain.
    insert image description here

Close a channel

The channel can use ok to detect whether the channel is still open. If the channel is closed, no data will be read.

insert image description here

  • num ,ok:=<-chCan detect if the channel is closed.

Notice

  • Channels do not need to be closed frequently like files. You should only close a channel when you really have no data to send, or when you want to explicitly end a range loop.
  • After closing the channel, data cannot be sent to the channel (causing a panic error and causing the receive function to return a zero value immediately):
  • After closing the channel, you can continue to receive data from the channel:
  • For a nil channel, both sending and receiving will be blocked.
    insert image description here
  • You can use range to traverse the channel and automatically jump out of the loop
    insert image description here

One-way channel

By default, channels are dual-access, that is, data can be sent to them as well as received from them.
However, we often see a channel passed as a parameter and the value is expected to be used unidirectionally, either to send data or to receive data. In this case, we can specify the direction of the channel. The declaration of a unidirectional chamel variable is very simple, as follows:

var ch1 chan int //ch1双向
var ch2 chan<-float64 //ch2单向,只能用于写float64数据
var ch3 <-chan int  //ch3单向,只能用于读int数据
  • 1
  • 2
  • 3

chan&lt;- means that data enters the pipeline. To write data into the pipeline, it is output to the caller.
&lt;-chan means data comes out of the pipe. For the caller, it gets the data from the pipe, which is of course input.
A channel can be implicitly converted to a one-way queue, which only receives or sends data. A one-way channel cannot be converted to a normal channel.

insert image description here

Using a single channel to implement the producer consumer model

insert image description here