This is a creation in
Article, where the information may have evolved or changed.
Concurrent concurrency
- Many people are directed at go hype high concurrency and can not help but, in fact, from the source of the analysis, goroutine only by the official implementation of the "thread pool." But then again, the stack memory footprint of each instance 4-5kb and the significant reduction in creation and destruction overhead due to the implementation mechanism are the root causes of the high concurrency that the go claims to be made. In addition, Goroutine's simplicity and ease of use also give developers great convenience at the language level.
Concurrency not parallel: Concurrency is not Parallelism
- Concurrency mainly has switching time slices to achieve "simultaneous" operation, in parallel is the direct use of multi-core multithreaded operation, but go can set the use of the number of cores to play a multi-core computer capabilities.
Goroutine pursues communication to share memory, rather than shared memory.
/*一个最最最最基本的goroutine*/package mainimport ( "fmt" "time")func main() { go Go() time.Sleep(2 * time.Second)}func Go() { fmt.Println("Go Go Go!!!")}
Channel
- Channel is the bridge of goroutine communication, mostly blocking synchronous
- Created by make, close closes
- Channel is a reference type
- You can use the for range to iterate through the channel
- Single or bidirectional channels can be set
- You can set the cache size so that no blocking occurs until it is filled
package mainimport ( "fmt")func main() { make(chanbool//make(chan [所存储的数据类型]) gofunc() { fmt.Println("Go Go Go!!!") true//把true给到c }() //把c取出来的操作,在这里会等待并发函数把数据给到c之后才执行,保证了并发线程结束后主线程才结束}
PackageMainImport("FMT")funcMain () {c: = Make(Chan BOOL)//make (chan [stored data type]), direct make is a two-way channel, but also can be saved and can take Go func() {FMT. Println ("Go Go Go!!!") C <-true //Give true to C Close(c)} () forV: =RangeC {FMT. Println (v)}//Be sure to pay attention somewhere to close the channel, otherwise it will become a deadlock, infinite wait}//The process of this function is this: Go keyword concurrent an anonymous function, then execute for-range, at this time for-range execution needs to wait for a C, in the anonymous function, true after C, immediately for-range can be executed, The output of this V (V is c), and immediately into the state of waiting for the next C, in the anonymous function, at this time closed C,for-range immediately received the signal C is closed, the entire function ends. Run result: Go Go GO!!!true
Channel is divided into cache and no cache
Channel with no cache
package mainimport ( "fmt")func main() { make(chanbool//这里为无缓存的channel gofunc() { fmt.Println("Go Go Go!!!") true }() //运行到这里的时候该取了,可实际还没有放进去,所以在等待,等待放入之后再执行取的操作,无缓存是阻塞的,c里的东西不被读掉,程序无法往下执行}
Swap the channel's storage and reading operations.
package mainimport ( "fmt")func main() { make(chanbool//这里为无缓存的channel gofunc() { fmt.Println("Go Go Go!!!") <-c }() true//无缓存是阻塞的,c里的东西不被读掉,程序无法往下执行}
The above two operations can output go Go go!!!
The reason is that the non-cached channel is blocked.
The channel with the cache
package mainimport ( "fmt")func main() { make(chanbool, 1//这就成了有缓存的channel了 gofunc() { fmt.Println("Go Go Go!!!") <-c }() true}//这个程序不会输出Go Go Go!!!//因为有缓存,所以channel的存和取的操作不是堵塞的,简单说,存了以后,爱读不读。程序都会往下接着走,读会等待,取不会等待哦!
So the change of the access operation order of C can output go go go!!! The
package mainimport ( "fmt")func main() { make(chanbool, 1//这就成了有缓存的channel了 gofunc() { fmt.Println("Go Go Go!!!") true }() <-c}
A classic multi-core concurrency program
PackageMainImport("FMT" "Runtime")funcMain () {runtime. Gomaxprocs (runtime. NUMCPU ())//Set the number of CPU cores used (get CPU cores for this machine)c: = Make(Chan BOOL) forI: =0; I <Ten; i++ {GoGo (c, i)}//When a core is a step-by-minute thread, a thread starts executing, but now it 's multicore, which is the one that executes the i=5 first, possibly the first, or the i=8, which is the variable assignment of the task.<-C}funcGo (cChan BOOL, indexint) {A: =1 forI: =0; I <100000000; i++ {A + = i} fmt. PRINTLN (index, a)ifindex = =9{C <-true //So this place is wrong, sometimes index=9 is not the last to execute. }}//The result of the output is indeterminate, because the order in which the index=9 is executed is indeterminate.
So how do we solve this problem?
Solution to use cache
PackageMainImport("FMT" "Runtime")funcMain () {runtime. Gomaxprocs (runtime. NUMCPU ()) c: = Make(Chan BOOL,Ten)//Cache count is ten forI: =0; I <Ten; i++ {GoGo (c, i)}//10 Threads executed forI: =0; I <Ten; i++ {<-c}//Take 10 times here}funcGo (cChan BOOL, indexint) {A: =1 forI: =0; I <100000000; i++ {A + = i} fmt. PRINTLN (Index, a) C <-true //Save here once}
Solution 2--using Waitgroup (in "Sync" package)
PackageMainImport("FMT" "Runtime" "Sync")funcMain () {runtime. Gomaxprocs (runtime. NUMCPU ()) WG: = Sync. waitgroup{} WG. Add(Ten)//Set up 10 additional task volumes forI: =0; I <Ten; i++ {GoGo (&WG, i)//channel is a reference type, but here the WG is not a reference type, so it's going to pass in the address} WG. Wait ()//Here to wait for the task to complete}funcGO (WG *sync. Waitgroup, Indexint) {A: =1 forI: =0; I <100000000; i++ {A + = i} fmt. PRINTLN (Index, a) WG. Done ()//Mark once done}
Select
- Can handle the sending and receiving of one or more channel
- Simultaneous processing of multiple available channel in a random order
- Free Select to block the main function
- can set timeout
Select is a control structure in go, similar to the switch statement used for communication. Each case must be a communication operation, either sent or received.
Select executes a running case randomly. If there is no case to run, it will block until there is one to run. A default clause should always be operational.
select { case communication clause : statement(s); case communication clause : statement(s); /* 你可以定义任意数量的 case */ default/* 可选 */ statement(s);}
The syntax for the SELECT statement is described below:
每个case都必须是一个通信所有channel表达式都会被求值所有被发送的表达式都会被求值如果任意某个通信可以进行,它就执行;其他被忽略。如果有多个case都可以运行,Select会随机公平地选出一个执行。其他不会执行。否则: 1、如果有default子句,则执行该语句。 2、如果没有default字句,select将阻塞,直到某个通信可以运行;Go不会重新对channel或值进行求值。
Instance
PackageMainImport "FMT"funcMain () {varC1, C2, C3Chan int varI1, I2int Select{ CaseI1 = <-c1:fmt. Printf ("Received", I1,"from c1\n") CaseC2 <-i2:fmt. Printf ("Sent", I2,"to c2\n") Casei3, OK: = (<-C3)://Same as:i3, OK: = <-c3 ifOK {fmt. Printf ("Received", i3,"from c3\n") }Else{FMT. Printf ("C3 is Closed\n") }default: FMT. Printf ("No communication\n") } }
The above output results are as follows:
no communication
How to set Timeouts
//set timeout Package mainimport ( "FMT" " time ") func Main () {c: = make (chan bool ) select {case V: = <-c:fmt. Println (v) case <-time. After (3 * time. Second): FMT. Println ( "timeout" ) //can set timeout, that is, more than the time that has not received the task to execute the statement
}} output: [ "go run Temp.go ' | done: 3.2158144 S] Timeout