Golang channels Tutorial "translated 100%"

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

The go language has built-in tools for writing concurrent programs. This function is called in the same address space before the go Declaration is placed on a function that needs to be called, so that the function executes as a separate concurrent thread. This thread is called Goroutine in the Go language. Here I would like to mention that concurrency does not always mean parallelism. Goroutines is the creation of a schema that can execute programs in parallel, with hardware permitting. This is a discussion of this topic: concurrency is not parallel.

Let's start with an example:

Func Main () {     //Start a goroutine and execute println concurrently     go println ("goroutine message")     println (" Main function message ")}
Garfielt translated 3 years ago 2 people top Top Well translated!

This program will output the main function Messageand or goroutine message. I say " or " because there are some characteristics of the goroutine. When you run a goroutine, the calling code (in our case it is the main function) does not wait for Goroutine to complete, but continues to run down. After calling the println, the main function ends its execution, which in the go language means that the program and all the spawned goroutines stop executing. However, before this occurs, Goroutine may have completed the execution of its code and output the Goroutine message character.

You understand that there must be a way to avoid this situation. This is the role of channels in the go language.

Garfielt translated 3 years ago 2 people top Top Well translated!

Channels Basic Knowledge

The channels is used to synchronize functions that execute concurrently and to provide a mechanism for some kind of value-sharing communication. Some features of channels: the type of element passed through the channel, the container (or buffer), and the direction of delivery are specified by the "<-" operator. You can use the built-in function make to assign a channel:

I: = make (chan int)       /By default the capacity is 0s: = yes (Chan string, 3)//Non-zero Capacityr: = Make (<-chan b OOL)          //can only read fromw: = Make (chan<-[]os. FileInfo)//can only write to
Channels is a first-class value (an object is created during runtime, can be passed as a parameter, returned from a child function, or can be assigned to a variable.) Can be used anywhere, like other values: as a structural element, a function parameter, a function return value, or even the type of another channel:
A channel which://  -can only write to//  -holds another channel as its VALUEC: = Make (chan<-chan bool) function accepts a channel as a parameterfunc readfromchannel (input <-chan string) {}//function returns a CHANNELFU NC getchannel () chan bool {     b: = Make (chan bool)     return B}
Cmy00cmy translated 3 years ago 1 people top Top Well translated! Other translation versions (1) Loading ...Pay extra attention to the <-operator when reading and writing the channel. Its position is related to the read and write operation of the channel variable. The following example indicates how it is used, but I would like to remind you that this code and will not be fully executed,, cause we'll talk later:
Func Main () {     c: = make (chan int)     C <-    //write Channel     val: = <-c//read from channel     println (val)}
Now we know what the channel is, how to create the channel and learn some basic operations. Now let's go back to the first example and see how the channel is helping us.
Func Main () {     //creates a channel to synchronize goroutine     done: = Make (chan bool)     //Perform output operation in Goroutine     go func () {          println ("goroutine message")          //tells the main function to complete execution.          This channel is visible in the Goroutine          //Because it is executed in the same address space.          Done <-True     } ()     println ("main function message")     <-done//wait for Goroutine to end}
This program will print 2 messages Shunliu. Why is it? Because the channel has no buffering (we don't specify its capacity). All operations that are based on an unbuffered channel will lock the operation until the output and receive are all ready. This is why the Unbuffered channel is also known as synchronization (synchronous). In our case, the operator <-in the main function will lock the program until Goroutine writes the data in the channel. Therefore, the program terminates only after the successful completion of the read operation. Cmy00cmy translated 3 years ago 2 people top Top Well translated! Other translation versions (1) Loading ...

In order to avoid the existence of a channel buffer where all read operations are completed without locking (if the buffer is empty) and the write operation also ends successfully (the buffer is dissatisfied), such a channel is called a non-synchronous channel. Here is an example to describe the difference between the two:

Func Main () {     message: = Make (Chan string)//unbuffered     Count: = 3     go func () {for          I: = 1; I <= count; i++ { C4/>fmt. PRINTLN ("Send Message")               message <-FMT. Sprintf ("Message%d", i)          }     } () Time     . Sleep (time. Second * 3) for     I: = 1; I <= count; i++ {          fmt. Println (<-message)     }}

In this example, the output information is a synchronous channel, and the program outputs the result:

Send message//wait 3 seconds message 1send messagesend messagemessage 2message 3

As you can see, after the channel is written in the first Goroutine, the other write operations in the same channel are locked until the first read operation is completed (about 3 seconds).

Now we provide a buffer to the channel of the output information, for example: the definition initialization row is changed to: message: = Make (Chan string, 2). The output of this program will change to:

Send Messagesend messagesend message//wait 3 seconds message 1message 2message 3

Here we see that all of the write operations do not wait for the first read operation of the buffer to end, and the channel allows all three messages to be stored. By modifying the channel container, we can limit the system output by controlling the total number of processing information.

Cmy00cmy translated 3 years ago 1 people top Top Well translated!

Dead lock

Now let's go back to the previous example of a read/write operation that did not run successfully:

Func Main () {     c: = make (chan int)     C <-    //write Channel     val: = <-c//Read channel     println (val)}
Once you run this program, you will get the following error:
Fatal Error:all Goroutines is asleep-deadlock!goroutine 1 [Chan Send]:main.main ()     /fullpathtofile/channelsio.go : 5 +0x54exit Status 2

This error is the deadlock we know. In this case, two goroutine wait for each other to release resources, causing both parties to be unable to continue running. The Go language detects this deadlock and gives an error at run time. This error is caused by the nature of the lock itself.

The code runs in a single thread at a time and runs on a line-by-row basis. The action written to the channel (c <-42) locks the execution of the entire program, because the write operation in the synchronous channel will not execute successfully until the reader is ready. Here, however, we create the reader on the next line of the write operation.

In order for the program to execute smoothly, we need to make the following changes:

Func Main () {     c: = make (chan int)          //Enables the write operation to be performed in another goroutine.     go func () {         c <-      } ()     val: = <-c     println (val)}
Cmy00cmy translated 3 years ago 2 people top Top Well translated!

The channels of the range and the closing of the channel

In the previous example, we sent multiple messages to the channel and read them, and the Code for the Reader section is as follows:

For i: = 1; I <= count; i++ {     FMT. Println (<-message)}

In order to avoid a deadlock while performing a read operation, we need to know the exact number of messages sent because we cannot read more data than the number of bars written. But this is inconvenient, and below we provide a more humane approach.

In the go language, there is a code called a range expression that allows a program to repeatedly declare arrays, strings, slices, graphs, and channel, repeating declarations that persist until the channel is closed. Take a look at the following example (although it cannot be performed yet):

Func Main () {     message: = Make (chan string)     count: = 3     go func () {for          I: = 1; I <= count; i++ {               mes Sage <-FMT. Sprintf ("Message%d", i)          }     } () for     msg: = Range message {          FMT. PRINTLN (msg)     }}
Cmy00cmy translated 3 years ago 3 people top Top Well translated! Unfortunately, this code does not work at this time. As we mentioned earlier, scope (range) runs only when the channel is closed. So we need to close the channel with the close function, and the program will look like this:
Go func () {for     I: = 1; I <= count; i++ {          message <-FMT. Sprintf ("Message%d", i)     }     Close (Message)} ()
Another benefit of closing the channel is that the read operation in the closed channel will not cause a lock, but always the default corresponding channel type value:
Done: = yes (chan bool) close (done)//does not produce a lock, prints two times false//Because false is the default value of type bool println (<-done) println (<-done)
This feature can be used to control goroutine synchronization, so let's review the previous synchronization examples:
Func main () {done     : = Make (chan bool)     go func () {          println ("goroutine message")          //We only care about the fact that there is transmission, Rather than the contents of the value. Done          <-true     } ()     println ("main function message")     
Here, the done channel is only used to synchronize program execution, not to send data. A similar example:
Func Main () {     //is not related to data content done     : = Make (chan struct{})     go func () {          println ("goroutine message")          // Send signal "I ' m Done"          Close (done)     } ()     println ("main function message")     

We closed the channel in the Goroutine, and the read operation does not generate a lock, so the main function can continue to execute.

Cmy00cmy translated 3 years ago 2 people top Top Well translated!

Multi-channel mode and channel selection

In real project development, you may need multiple goroutine and channel. When the independence of each part is stronger, the more efficient synchronization measures are needed between them. Let's look at a slightly more complex example:

Func Getmessageschannel (msg string, delay time. Duration) <-chan String {     c: = Make (chan string)     go func () {for          I: = 1; I <= 3; i++ {               c <-fmt.s printf ("%s%d", MSG, i)               //wait for time before sending the message               . Sleep (time. Millisecond * delay)          }     } ()     return C}func main () {     C1: = Getmessageschannel ("First", +)     C2: = Getmessageschannel ("Second", C3)     : = Getmessageschannel ("Third", ten) for     i: = 1; I <= 3; i++ {          printl N (<-C1)          println (<-C2)          println (<-C3)     }}
Here we create a method to create the channel and define a goroutine that sends three messages to the channel in one of these calls. We see that C3 is supposed to be the last channel call, so its output information should be before other information. But what we get is the following output:
First 1second 1third 1first 2second 2third 2first 3second 3third 3
Cmy00cmy translated 3 years ago 1 people top Top Well translated!

Obviously we have successfully exported all the information because the read operation in the first channel is locked for 300 milliseconds in each loop declaration, and the other operation must go into the wait state. What we expect is to read the information as quickly as possible from all channel.

We can use Select to choose between Multiple channel. This option is similar to a normal switch, but all cases here are numeric pass operations (read/write). Even if the number of operands increases, the program will not run under more locks. Therefore, if you want to achieve our previous purpose, we can rewrite the program as follows:

For i: = 1; I <= 9; i++ {     Select {case     msg: = <-c1:          println (msg) Case     msg: = <-c2:          println (msg) Case     msg: = & LT;-C3:          println (msg)     }}
Cmy00cmy translated 3 years ago 1 people top Top Well translated!

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.