Golang co-process
Learning Golang also has a period of time, here to talk about the Golang process of the use of understanding, Golang Many people know, after all, there is a good dad Google, mention Golang and other languages The biggest difference is goroutine,
That is the go process, first a demo
package mainfunc say(s string) { for i := 0; i < 5; i++ { println(s) }}func main() { go say("Hello") go say("World")}
The way to start the process is to use the keyword go, followed by a function or similar to the following anonymous function notation
go func() { for i := 0; i < 5; i++ { println(i) }}()
Of course, if you run the first piece of code above, you will find what results are not, what???
This at least indicates that your code is not a problem, when you use go to start the process, the 2 functions are switched to the process inside the execution, but this time the main thread is over, the 2 of the process has not been executed before the hang!
The smart little Buddy will think, that I main thread first sleep 1s wait? Yes, in the last line of the main code block, add:
time.Sleep(time.Second*1) # 表示睡眠1s
You will find that you can print out 5 Hello and 5 world, running multiple times you will find that the order of Hello and world is not fixed, which further illustrates the problem that multiple processes are executed concurrently
But sleep this way certainly is not reliable, go comes with a waitgroup can solve this problem, the code is as follows:
package mainimport ( "sync")var wg sync.WaitGroupfunc say(s string) { for i := 0; i < 5; i++ { println(s) } wg.Done()}func main() { wg.Add(2) go say("Hello") go say("World") wg.Wait()}
For a brief explanation of usage, VAR is declaring a global variable WG, which is type sync. Waitgroup,wg.add (2) is that I have 2 goroutine to execute,
Wg. Done equals WG. ADD (-1) means I'm done with this process. Wg. Wait () is to tell the main thread to wait, until they are 2 to execute and then exit.
For example, you have a need to take different data from 3 libraries to summarize processing, synchronous code is written to check 3 times the library, but these 3 queries must be executed sequentially, most programming language code execution order is from top to bottom, if a
Query time-consuming 1s,3 query is 3s, but the use of the process you can make these 3 queries at the same time, that is 1s can be done (if the database to keep up). There is also an example of a more practical use to write crawlers.
However, in order to better use the process, you may also have to understand the pipeline Chanel,go inside the pipeline is the communication channel between the process, the above example we are directly printed out the results, if the current demand is to return the output to the main thread?
package mainimport ( "sync")var wg sync.WaitGroupfunc say(s string, c chan string) { for i := 0; i < 5; i++ { c <- s } wg.Done()}func main() { wg.Add(2) ch := make(chan string) // 实例化一个管道 go say("Hello", ch) go say("World", ch) for { println(<-ch) //循环从管道取数据 } wg.Wait()}
Briefly, here is the instantiation of a pipeline, the go-initiated coprocessor simultaneously outputs data to this 2 pipeline, the main thread uses a for loop to fetch data from the pipeline, which is actually a producer and consumer pattern, and the Redis queue is a bit like
It is worth saying that the order of the world and Hello into the pipeline is not fixed, you may be in the experiment when the discovery seems to be fixed, it is because the computer ran too fast, you put the loop data amplification, or in the inside add a sleep and then see
However, this program is bug-like and will be output at the end of the program's run:
Error message prompt means that all the co-process are asleep, the program to monitor the deadlock! Why is that? I understand that the go pipeline is blocked by default (if you do not set the cache), you put one over there, I can take one of the first,
If you put something on that side no one to take, the program will be waiting, the deadlock, at the same time, if there is no one to put things, you can not take this side, also will occur deadlock!
How to solve this problem? The standard practice is to actively shut down the pipe, or you know when you should close the pipe, and of course your end of the program pipeline will naturally turn off! For the demo code above, you can write this:
i := 1for { str := <- ch println(str) if i >= 10{ close(ch) break } i++}
Because we clearly know that the total output of 10 words, so here is a simple judgment, more than 10 to close the pipe exit For loop, will not error! Here is an example of using Select to fetch data from a pipeline:
package mainimport ( "strconv" "fmt" "time")func main() { ch1 := make(chan int) ch2 := make(chan string) go pump1(ch1) go pump2(ch2) go suck(ch1, ch2) time.Sleep(time.Duration(time.Second*30))}func pump1(ch chan int) { for i := 0; ; i++ { ch <- i * 2 time.Sleep(time.Duration(time.Second)) }}func pump2(ch chan string) { for i := 0; ; i++ { ch <- strconv.Itoa(i+5) time.Sleep(time.Duration(time.Second)) }}func suck(ch1 chan int, ch2 chan string) { chRate := time.Tick(time.Duration(time.Second*5)) // 定时器 for { select { case v := <-ch1: fmt.Printf("Received on channel 1: %d\n", v) case v := <-ch2: fmt.Printf("Received on channel 2: %s\n", v) case <-chRate: fmt.Printf("Log log...\n") } }}
The output results are as follows:
Received on channel 1: 0Received on channel 2: 5Received on channel 2: 6Received on channel 1: 2Received on channel 1: 4Received on channel 2: 7Received on channel 1: 6Received on channel 2: 8Received on channel 2: 9Received on channel 1: 8Log log...Received on channel 2: 10Received on channel 1: 10Received on channel 1: 12Received on channel 2: 11Received on channel 2: 12Received on channel 1: 14
This program built 2 pipelines a transmission int, a transmission string, while starting 3 co-processes, the first 2 is very simple, that is, every 1s to the pipeline output data, the third process is constantly from the pipeline to fetch data,
Unlike the previous example, PUMP1 and PUMP2 are 2 different pipelines that can be switched between different pipelines through Select, which pipe has data from which pipe to fetch data, and if no data is waiting,
There is also a timer function that can output content to the pipeline every once in a while!
Finally, it is worth saying that the go comes with the Web server performance is very strong, mainly because the use of the process, for each Web request, the server will open a new go process to handle,
A server can easily open at the same time tens of thousands of processes, well, say so much, interested in an in-depth look at golang!