Using the Goroutine method is very simple, directly before the statement with the GO keyword, if it is a multi-core processor computer, using Gorountine, will be executed on another CPU goroutine, the sub-process does not necessarily and the main process on a CPU.
Here are two things to note, the process using the GO keyword is called a subprocess, and the process without the GO keyword is called the main coprocessor, and on a multi-CPU machine, if there are multiple threads, then the order of execution and the order of execution are indeterminate, but one thing, if the main thread ends, Then the whole process is over, regardless of whether the sub-process is over or not, and the entire progress is over, and the results of the sub-processes are not seen.
Example 1
Package Mainimport "FMT" Func main () {go FMT. Println ("Hello") //Sub-process FMT. PRINTLN ("World")//main co-process}
After the above code executes, there are three results:
1. Hello World 2, World 3, World Hello
All three of these results are correct.
For the first, the sub-process executes output hello on one CPU and then the output world in the main process.
For the second, the sub-process on a CPU did not have time to execute, or did not perform the completion, but the main coprocessor has been completed, at this time the entire session is finished running, so you can not see the results of the sub-process.
For the third, when the statement in the main process has not been completed, the sub-process has been run, almost at the same time, so there will be this situation.
You can refer to the following diagram to understand:
Create Channel
The 0 value of the channel is nil.
Chi: = made (chan int) CHS: = Made (Chan string) Chif: = Make (chan interface{})//Because all types can be considered to have an empty interface// So this chif Chan receives any kind of Chan
Send and Receive Channel
Chi: = make (chan int) chi <-3//send i: = <-chi//Receive, save value <-chi//receive, do not save value
Close Channel
Chi: = make (chan int) Chi <-3 //Send I: = <-chi//Receive, save value <-chi //Receive, do not save value Close (CHI)//Close Channel
Sending data to a channel that has been closed can cause panic exceptions. For a channel that has been closed, you can continue to receive data from the closed channel, and if there is no data, the 0 value of the Chan type is received.
No cache channel (synchronous channel)
A channel that is based on no cache:
1, the sending operation will cause the sender's gorountine to block, until there are two outside a goroutine on the same channel to perform the receive operation, the sender's blocking will be solved.
2, similarly, if the receiving operation occurs first, then the recipient Goroutine will also block until another goroutine on the same channel to perform the send operation, the receiver's blocking will be solved.
Send and receive operations based on a non-cached channel will cause two goroutine to do a synchronous operation, so it is also called a synchronous channel.
Send multiple data to an unbuffered channel, that is, multiple goroutine are sending data to the same goroutine, and there is only one process to receive data, what is the problem after this time? Will overwrite occur? Or is only the first value sent to be retained, and the data sent later is invalid? What's the difference between having a cache channel?
Take a look at the following example:
Package Mainimport "FMT" Func Main () {chi: = make (chan int)//unbuffered go func () {chi <-10chi <-30chi <-+} ()//fmt. Println (<-chi)//10//fmt. Println (<-chi, <-chi)//10 30//fmt. Println (<-chi, <-chi, <-chi)//10 40fmt. Println (<-chi, <-chi, <-chi, <-chi)//deadlock}
As you can see from the example above, there is a gorountine to send three data to an unbuffered channel, in this case:
0. When Chi has not been able to send data to the channel, the main process is blocked and the sub-process can send a data to it.
1. The main process receives the data only once from the channel: the sub-process sends a data to Chi, at which time it is blocked from the coprocessor and waits for the data in Chi to be consumed before it continues to run. Then, the first data received by the main coprocessor is the first data sent to the Channel 10, after the channel is idle, the sender can send a second data 30, the sub-process is blocked again, waiting for the main process to receive data, but at this time the main process does not accept the data, the main process has been completed, Then the whole process is finished, so the final output is only 10 of this data. The sub-process is then ended.
2, the main process only receives two data from the channel: Then the previous step, at this time the main process receives the data for the second time, the received is 30; then, after the Chi is idle, the sub-process sends the data 40 again to Chi, and then blocks, but the main process is complete, and the sub-process is closed again.
3, the main process receives three data from the channel: Then the previous step, at this time the main process received the data should be 40, after the Chi Idle, the sub-process will not send data like it, at the same time, the sub-process has already run the end, so the main process output 10 30 40.
4, the main process receives four data from the channel: Then the previous step, because Chi is free, and the sub-process has ended, indicating that there is no association to send data to Chi, but Chi is not closed, then the fourth time in the main process of receiving data will wait, resulting in deadlock. Solve this problem, you can send the third data in the sub-process 40, after the close (CHI), after the main process to receive data for the fourth time will not cause a deadlock, received data 0 (Chi of type 0 value)
Use range to traverse Channel
Package Mainimport ("FMT") func main () {num: = do (chan int) go func () {num <-30num <-40close (num)} () for x: = Range num {fmt. PRINTLN (x)}//output//30//40}
When using range to traverse the channel, the data is received from the channel, and if the data is obtained from the channel, the returned result is the obtained value, and if the channel is closed, no data is available for the unbuffered channel. But the result of range is the type 0 value of the channel.
Series Channel
The following is a series channel that implements
Package Mainimport ("FMT", "Time") Func main () {num: = make (chan int) sqrt: = Do (chan int) go func () {for x: = 0;; x + + = num <-Xtime. Sleep (time. Second)}} () go func () {for {x: = <-numsqrt <-x * ×}} () for {fmt. Println (<-SQRT)}}
In this code, there is a problem: if the first sub-process no longer sends data to NUM, then the second sub-process will block, in the same way, the main sqrt fetch data will block, and eventually trigger a deadlock.
Workaround:
Package Mainimport ("FMT", "Time") Func main () {num: = make (chan int) sqrt: = Do (chan int) go func () {for x: = 0; x < 10; x + + {num <-xtime. Sleep (time. Second)}//Close the channel when no longer sending data to NUM, prevent deadlock close (num)} () go func () {for x: = Range num {sqrt <-x * x}//num is closed, so also close SQRTCL OSE (SQRT)} () for x: = range sqrt {fmt. PRINTLN (x)}}
Unidirectional Channel
When using channel as a parameter to communicate, in the function, some channel only accepts the data, some channel only sends the data, this can use one-way channel expression.
Two-way channel: Because the close channel operation is usually the sender notifies the receiver, the sender no longer sends new data to the channel, so the close function is usually called only at the Goroutine where the sender is located. It is obviously unreasonable to close the channel in the Goroutine receiving the channel data, which is likely to cause an error because the goroutine that sent the data may not know that the channel is closed, so once he sends the data to Channle, it throws an error.
Unidirectional channel: Only the Goroutine in the sender can call the close function to close a single channel. If a goroutine, call the Close function on a channel that is only accepted, or throw a compilation error.
Any two-way channel assignment to a one-way channel will result in an implicit conversion, but not a reverse conversion.
Declaring one-way Channle
Chi: = make (<-chan int)//Channelchi only read data: = Make (chan <-int)//channel receiving data only
A buffered channel.
Chi: = make (chan int)//unbuffered Chii: = Do (chan int,10)//have cache channel, cache space can store 10 values
After a cached channel has been defined:
When the data is sent to the channel, only if the number of buffers in the channel is not 0 o'clock, the data can be written, and the goroutine of the writing data will not block.
When reading data from the channel, the Goroutine of the channel is not blocked until the channel is empty.
Package Mainimport ("FMT" "Time") func writedata (chi Chan int) {go func () {for x: = 0;; x + + + Chi <-xtime. Sleep (2 * time. Second)}} () go func () {for x: = 0;; x + +, Chi <-xtime. Sleep (time. Second)}} () go func () {for x: = 0;; x + +, Chi <-xtime. Sleep (2 * time. Second)}} ()}func main () {chi: = Make (Chan int., 3) WriteData (CHI) for x: = Range Chi {fmt. PRINTLN (x)}}
In this example, if the channel is full when the data is written, the goroutine of the write data is blocked. If the channel is empty when the channel is read, then the goroutine of the read data is blocked.
Loops in concurrency
Package Mainimport "FMT" func-loop () {for x: = 0; x < ten; PRINTLN (x)} ()}}func main () {loop ()}
When the above code executes, the following problems may occur:
1, no output 2, only a portion of the output value 3, the output of a lot of the same value 4, the output of the same value
For 1, 2, 3 of the problem, is because the main process execution speed is too fast, the various goroutine have not time to execute, the main process is over, so the entire progress is over, also can not see the output.
Workaround: Add a sleep to the main process, and give each time to execute.
Package Mainimport ("FMT" "Time") Func-loop () {for x: = 0; x <; PRINTLN (x)} ()}}func main () {loop () time. Sleep (time. Second)}
For the fourth question, because loops in the loop are too fast, and each goroutine too slow, so all goroutine before execution, the loop is finished, at this time I is 10, so all print 10.
Workaround: Use I as a parameter (closure)
Package Mainimport ("FMT" "Time") Func-loop () {for x: = 0; x < n + + + = {go func (i int) {//i is the parameter fmt. Println (i)} (x)//x is argument}}func main () {loop () time. Sleep (time. Second)}
Select Receive Channel
Package Mainimport ("FMT") func-loop (ch Chan int, chi Chan int) {go func () {for {ch <-9}} () go func () {for {Chi <-8} } ()}func main () {ch, Chi: = Make (Chan int.), make (chan int) loop (ch, chi) Select {case <-ch:fmt. PRINTLN ("Data received in CH") Case <-chi:fmt. Println ("Received data in Chi")}}
A select is similar to if else, and each case represents the data that receives the channel and performs the corresponding operation. But in the above example, it is only accepted once, either by CH, or by Chi, and then no more data is read from the channel.
If you are waiting to receive multiple channel, that is, to receive data from multiple channel, you can use a for + select:
Package Mainimport ("FMT" "Time") func loop (Ch Chan int., chi Chan int) {go func () {for {ch <-9time. Sleep (2 * time. Second)}} () go func () {for {Chi <-8time. Sleep (3 * time. Second)}} ()}func main () {ch, Chi: = Make (Chan int.), make (chan int) loop (ch, chi) for {select {case <-ch:fmt. PRINTLN ("Data received in CH") Case <-chi:fmt. Println ("Received data in Chi")}}}
Concurrent exit
Package Mainimport ("FMT" "Time") Func main () {exit: = Make (chan bool) for x: = 1; x < 5 {Case <-exit:fmt. Println ("First", I, "Goroutine End Run") returndefault:fmt. Println ("First", I, "Goroutine running")}time. Sleep (time. Second)}} (x)}time. Sleep (time. Second * 5) //each goroutine run close (exit) //Broadcast end message time. Sleep (time. Second * 1) //wait for each goroutine to print end information}