This is a creation in Article, where the information may have evolved or changed.
Concurrent
Some people compare go to the C language of the 21st century, the first is because the go language design is simple, second, the 21st century most important is the parallel programming, and go from the language level to support the parallel.
Goroutine
Goroutine is the core of go parallel design. Goroutine In fact is a thread, but it is smaller than the thread, more than 10 goroutine may be reflected in the bottom is five or six threads, the go language inside to help you achieve the memory sharing between these goroutine. Execution goroutine requires very little stack memory (presumably 4~5kb) and will, of course, scale according to the corresponding data. Because of this, thousands of concurrent tasks can be run concurrently. Goroutine is easier to use, more efficient and lighter than thread.
Goroutine is a thread manager managed through the runtime of Go. Goroutine go
is implemented by the keyword, which is actually a normal function.
Go Hello (A, B, c)
A goroutine is launched via the keyword go. Let's look at an example
Package Mainimport ( "FMT" "runtime") Func say (s string) {for I: = 0; i < 5; i++ { runtime. Gosched () FMT. Println (s) }}func main () { go Say ("world")//Open a new Goroutines execution say ("Hello")//current Goroutines execution}// After executing the above program will output://hello//world//hello//world//hello//world//hello//world//Hello
We can see that the Go keyword is very handy for concurrent programming. The above multiple goroutine run in the same process, sharing the memory data, but the design we want to follow: do not communicate through sharing, but to be shared through communication.
runtime. Gosched () means that the CPU will give the time slice to others, and the next time it resumes executing the goroutine.
By default, the scheduler uses only a single thread, meaning that only concurrency is implemented. To play parallel with multicore processors, you need to explicitly call runtime in our program. Gomaxprocs (N) tells the scheduler to use multiple threads at the same time. Gomaxprocs sets the maximum number of system threads that are running logic code at the same time, and returns the previous settings. If n < 1, the current setting is not changed. After the schedule is improved in the new version of Go, this is removed. Here's an article about concurrency and parallelism that Rob introduces: Http://concur.rspace.googlecode.com/hg/talk/concur.html#landing-slide
Channels
The goroutine runs in the same address space, so access to shared memory must be well synchronized. So how does data communicate between Goroutine, go provides a good communication mechanism channel. The channel can be analogous to a bidirectional pipeline in a Unix shell: it can send or receive values. These values can only be of a specific type: Channel type. When defining a channel, you also need to define the type of value sent to the channel. Note that you must use make to create the channel:
CI: = make (chan int) cs: = Do (chan string) CF: = Make (chan interface{})
Channel via operator <-
to receive and send data
Ch <-v //Send V to channel CH.V: = <-ch //Receive data from CH and assign to V
Let's apply these to our example:
package mainimport" FMT "func sum (a []int, C Chan int) {total: = 0 for _, V: = RA Nge a {total + = v} c <-Total//Send all to C}func main () {a: = []int{7, 2, 8,-9, 4, 0} c: = Make (chan int) go sum (A[:len (a)/2], C) Go sum (A[len (a)/2:], c) x, y: = <-c, <-c//Receive from C FMT. Println (x, y, x + y)}
By default, the channel receives and sends data to be blocked, unless the other end is ready, which makes the Goroutines synchronization much simpler, without the need for an explicit lock. The so-called blocking, that is, if read (value: = <-ch) It will be blocked until data is received. Second, any send (ch<-5) will be blocked until the data is read out. Unbuffered Channel is a great tool for synchronizing between multiple goroutine.
Buffered Channels
We have described the default non-cached channel, but go also allows you to specify the buffer size of the channel, which is simply how many elements the channel can store. ch:= make (chan bool, 4) Creates a bool-type channel that can store 4 elements. In this channel, the first 4 elements can be written without blocking. When the 5th element is written, the code blocks until the other goroutine reads some elements from the channel, freeing up space.
CH: = Make (chan type, value) value = = 0! No buffering (blocking) value > 0! Buffering (non-blocking until value elements)
Let's take a look at the following example, you can test it on your own machine, modify the corresponding value value
Package Mainimport "FMT" Func Main () { c: = make (chan int, 2)//modify 2 to 1 for error, modify 2 to 3 to operate normally C <- 1 c <-2 FMT . Println (<-c) FMT. Println (<-C)} //modified to 1 reported error: //fatal error:all Goroutines is asleep-deadlock!
Range and close
In this example, we need to read two times C, which is not very convenient, go considering this, so you can also use range, like operation slice or map to manipulate the buffer type of channel, see the following example
package mainimport (" FMT ") func Fibonacci (n int, c Chan int) {x, Y: = 1, 1 fo R I: = 0; I < n; i++ {c <-x x, y = y, x + y} close (c)}func main () {c: = make (chan int, ten) go Fibonacci (ca P (c), C) for I: = Range C {fmt. Println (i)}}
for I: = range C
is able to continuously read the data inside the channel until the channel is explicitly closed. The above code we see can be explicitly closed channel, producer via built-in function close
to close the channel. After the channel is closed, no more data can be sent, in the consumer's grammar v, OK: = <-ch
The test channel is closed. If OK returns false, then the channel has no data and has been closed.
Remember that the channel should be closed at the producer's place, not where it is consumed, so it can easily cause panic
Another thing to remember is that the channel is not like a file, and you don't have to close it often, only if you really don't have any data to send, or you want to explicitly end the range loop.
Select
What we've described above is only one channel, so if there's more than one channel, how do we do it, and go provides a keyword select
, through select
can listen for data flow on the channel.
select
is blocked by default and only runs when there is a send or receive in the channel being monitored, and when multiple channel is ready, select is randomly selected to execute.
package mainimport" FMT "func Fibonacci (c, quit Chan int) {x, Y: = 1, 1 for { Select {Case C <-x:x, y = y, x + y case <-quit:fmt. Println ("Quit") return}}}func main () {c: = Make (Chan int.) Quit: = make (chan int) go func ( {for I: = 0; i <; i++ {FMT. Println (<-C)} quit <-0} () Fibonacci (C, quit)}
There is the default select
syntax, in select
fact, is similar to switch function, the default is when the channel is not ready to listen to the time, the defaults (select no longer block waiting for the channel).
Select {case I: = <-c: //Use Idefault: //When C is blocked execute here}
Timeout
Sometimes there is a case of goroutine blocking, so how do we avoid the whole program getting stuck? We can use Select to set the timeout, which is implemented in the following way:
Func Main () { c: = Make (chan int.) o: = Make (chan bool) go func () {for { Select {case V: = <- C: println (v) Case <-time. After (5 * time. Second): println ("timeout") o <-true break } }} () <-o}
Runtime Goroutine
There are several functions in the runtime package that deal with Goroutine:
Goexit
Exits the currently executing goroutine, but the defer function also continues to invoke the
Gosched
With the execution permission of the current goroutine, the scheduler schedules other waiting tasks to run and resumes execution from that location at some point.
Numcpu
Returns the number of CPU cores
Numgoroutine
Returns the total number of tasks being executed and queued
Gomaxprocs
Used to set the maximum number of CPU cores that can be computed in parallel and return the previous value.