Basic rules of GO channel best practices

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

channel[Channel] is an important feature of Golang, precisely because the existence of the channel makes Golang different from other languages. Channel makes concurrent programming easy and fun.

The concept and syntax of channel

A channel can be understood as a FIFO message queue. The channel is used to pass data before the [Goroutine] process, which is, to be precise, the ownership of the data. A well-designed program should ensure that the data in the channel at the same time is only owned by the same co-process, thus avoiding data insecurity problems associated with concurrency [data races].

Type of Channel

Like arrays, slices, and dictionaries, the channel type is a combination type, and each channel type corresponds to a simple data type. For example, if the type of the element is string, then the corresponding channel type is Chan string, and the data that enters the channel must be a string type value.

The official go compiler restricts a single element in the channel by up to 65,535 bytes, which means that if the channel buffer array contains a struct, the struct's size cannot be larger than 65535. However, we should not pass an oversized element value, as the channel data from entry to outflow involves data copy operations. If the element size is too large, the best method is to use the pass-through pointer instead of passing the value.

The channel type can have a direction, assuming T is a type

    1. Chan T is a two-way channel type, and the compiler allows simultaneous sending and receiving of two-way channel.
    2. chan<-T is a write-only channel type, and the compiler only allows data to be sent to the channel.
    3. <-chan T is a read-only channel type, and the editor only allows data to be received from the channel.

The two-way channel, which can be coerced into a read-only channel or a write channel only, is not, in turn, a read-only and write-only channel that cannot be converted into a two-way channel.

The 0-value form of the channel type is called the empty channel. A non-empty channel type must be created with the Make keyword. For example make (chan int, 10) will create a channel that can hold 10 int values. The second shaping parameter value represents the size of the channel that can hold the data, and if this parameter value is not provided, then the default value is zero.

varchchanstring;// nil channelch:=make(chanstring);// zero channelch:=make(chanstring,10);// buffered channel

The volume of value buffer inside the channel is the channel capacity. The channel's capacity is zero to indicate that this is a blocking channel, non-zero represents a buffered channel [non-blocking channel].

Channel internal structure

Each channel internal implementation has three queues

    1. The thread queue that receives the message. The structure of this queue is a list of the maximum length, and all the threads blocking the channel's receive operation will be placed in this queue.
    2. The thread queue that sends the message. The structure of this queue is also a linked list with the maximum length. All the threads that are blocking the transmit operation of the channel will also be placed in this queue.
    3. Ring Data buffer queue. The size of this ring array is the channel's capacity. If the array is full, the channel is full, and if a value is not in the array, it means that the channel is empty. For a blocking channel, it is always in the full and empty state at the same time.

A channel is referenced by all the processes that use it, that is, the channel is never garbage collected as long as the two queue lengths with the co-threads are greater than 0. In addition, if the process itself is blocked on the channel's read and write operations, the process will never be garbage collected, even if the channel is only referenced by this one.

Use of Channel

Channel supports the following operations

    1. Using the CAP (CH) function to query the channel's capacity, cap is the built-in function of Golang
    2. Using the Len (CH) function to query the length of the data inside the channel, the Len function is also built-in, and the function on the surface is very meaningful, but it is seldom used.
    3. Closing channel,close with close (CH) is also a built-in function. A non-empty channel can only be closed once, and if closing an empty channel that has been closed or closed, it will cause panic. Additionally closing a read-only channel is illegal and the compiler directly complains.
    4. Use ch <-v to send a value V to channel. Sending a value to the channel can have multiple results, which can be successful, may also block, and even cause panic, depending on what state the current channel is in.
    5. Using V, OK <-ch receives a value. The second traversal OK is optional, which indicates whether the channel is closed. The received value will only have two more results, either successfully or blocked, and will never cause panic.

All of these operations are synchronous and are secure and do not require any additional synchronization controls.

For-range

The For-range syntax can be used on the channel. The loop will always receive data from the channel until the channel is closed. A for-range that differs from For-range,channel on Array/slice/map allows only one variable.

forv=rangeaChannel{// use v}

Equivalent to

for{v,ok=<-aChannelif!ok{break}// use v}

Note that the for-range corresponding channel cannot be a write-only channel.

Select-cases

The Select Block is a specially designed syntax for the channel, which is very similar to the switch syntax. They can have more than one case block on a branch and a default block, but there are many different

    1. There must be no expression between select and parentheses {
    2. Fallthrough keyword cannot be used in select
    3. All case statements are either the send operation of the channel or the receive operation of the channel
    4. The case statements in select are executed randomly, not sequentially. Imagine that if the channel of the first case statement is non-blocking, the sequential execution of the case statement causes the subsequent case statement to be executed until the value in the channel corresponding to the first case statement is exhausted.
    5. If all the action associated with the case statement is blocked, the default branch is executed. If there is no default branch, the current goroutine is blocked and the current goroutine is hooked up to the coprocessor queue within all the associated channel. So a single goroutine can be attached to multiple channel at the same time, and can even be attached to the same channel at the same time the sending and receiving the queue of the coprocessor. When a blocked goroutine gets a data contact block, it is removed from all relevant channel queues.

Channel Simple rule table

The active channel of the subscript indicates that the channel is non-empty and not closed

Detailed explanation of channel rules

Empty Channel

    1. Closing an empty channel causes the current goroutine to be raised panic
    2. Sending a value to an empty channel causes the current goroutine to block
    3. Receiving values from an empty channel can also cause the current goroutine to block

The call Len and the CAP function on the empty channel all return zero uniformly.

The channel that has been closed

    1. Closing a closed channel will cause panic
    2. Sending a value to a closed channel will cause panic. When this send operation is placed on a case statement inside a select block, it causes the SELECT statement to throw panic at any time.
    3. Receiving a value from a closed channel is neither blocked nor panic, it has been able to return successfully. Just returning the second value OK is always false, indicating that the received V is obtained after the channel is closed, and the corresponding value is the 0 value of the corresponding element type. You can receive a value from an infinite loop from a closed channel.

The Active Channel

    1. Close operation
      1. Removes all goroutine from the channel's receive coprocessor queue and wakes them up.
      2. Removes all goroutine from the channel's receive coprocessor queue and wakes them up.
      3. A buffered array inside a closed channel may not be empty, and those values that are not received will cause the channel object to never be garbage collected.
    2. Send action
      1. In the case of a blocking channel, remove the first one from the channel's receive-Path queue and pass the sent value directly to the process.
      2. If it is a blocking channel, and the receive-path queue of the channel is empty, then the current coprocessor will be blocked and entered into the channel's sending coprocessor queue.
      3. If it is a buffered channel, and there is room in the buffer array, then the sent value is added to the array at the end and the current process is not blocked.
      4. If it is a buffered channel, and the buffer array is full, the current process will be blocked and entered into the channel's sending coprocessor queue.
    3. Receive operation
      1. If the buffer channel is buffered and the buffer array has values, the current coprocessor is not blocked and the first value is taken directly from the array. If the send queue is not empty, you also need to wake the first goroutine in the queue.
      2. If it is a blocking channel and the sending queue is not empty, then the first process of waking up the send queue will pass the value sent directly to the received coprocessor.
      3. If it is a buffered channel, and the buffer array is empty, or if it is a blocking channel, and the sending coprocessor queue is empty, then the current process will be blocked and added to the channel's receive coprocessor queue.

Summarize

According to the above rules, we can draw the following conclusions

    1. If the channel is closed, its receive and send queue must be empty, but its buffer array may not be empty.
    2. The channel receives the queue and buffer array, the same time must have one is empty
    3. If the buffer array for the channel is not full, then its send-to-process queue must be empty.
    4. For a buffered channel, the same time it receives and sends a queue of threads, there must be an empty
    5. For non-buffered channel, it is generally the same time its receiving and sending the queue, there must be an empty, but there is an exception, that is, when its send operation and receive operations in the same select block, two queues are not empty.

Click to view the original English version

Read more articles about the "code hole" of the column

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.