Concurrency in Go language refers to the ability to make a function run independently of other functions. When a function is created as a coroutine, the Go language will treat it as an independent unit of work, which will be scheduled to be executed on the available logic processor.
Fundamentals of concurrent programming
1. Concurrency and parallelism (theory not understood)
Understanding the thread s and process es of the operating system is helpful to understand how the Go language runtime scheduler can use the operating system to run goroutine concurrently.
Parallelism is to let different code fragments execute on different physical processors at the same time. The key to parallelism is to do many things at the same time, while concurrency refers to managing many things at the same time. These things may be suspended to do other things after only half of them are done.
Using less resources to do more is the philosophy guiding Go language design.
2. Specifies the number of cores to use
Go language will call the number of CPU cores by default. These functions are automatically adjusted, but corresponding standard libraries are also provided to specify the number of cores. Using flags package, you can adjust the number of CPU cores called when the program runs.
The code is as follows:
package main import ( "fmt" "time" ) func longWait() { fmt.Println("start longWait()") time.Sleep(5 * 1e9) fmt.Println("end longWait()") } func shortWait() { fmt.Println("start shortWait()") time.Sleep(2 * 1e9) fmt.Println("end shortWait()") } func main() { fmt.Println("Here is main()Where to start") go longWait() go shortWait() fmt.Println("Hang main()") time.Sleep(10 * 1e9) fmt.Println("Here is main()Where it ends") }
The main(), longWait() and shortWait() functions are started in sequence as independent processing units, and then run in parallel. Each function outputs messages at the beginning and end of the run.
The operation results are as follows:
Here is main()Where to start Hang main() start longWait() start shortWait() end shortWait() end longWait() Here is main()Where it ends
If you remove the go language keyword, run the program again:
Here is main()Where to start start longWait() end longWait() start shortWait() end shortWait() Hang main() Here is main()Where it ends
goroutine
The operating system is in charge of the process, the thread in the process and the coroutine in the process.
The biggest advantage of collaborative process is its "lightweight", which can easily create millions of collaborative processes without causing system resource exhaustion, and the maximum number of threads and processes can not exceed 10000.
Go language supports lightweight threads at the language level, called goroutine.
1. Synergetic basis
goroutine is the core of Go language parallel design.
goroutine is a thread manager managed through the runtime of the Go program. goroutine is implemented through the go keyword. In fact, it is an ordinary function.
The code is as follows:
package main import ( "fmt" "runtime" ) func say(s string) { for i := 0; i < 5; i++ { runtime.Gosched() fmt.Println(s) } } func main() { go say("world") say("hello") }
The running results are as follows: different from books.
hello hello hello hello hello
Books are:
hello world hello world hello world hello world hello
2. Inter process communication
There are usually two most common concurrent communication models: shared data and messages.
The code is as follows:
package main import ( "fmt" "runtime" "sync" ) var counter int = 0 func Count(lock *sync.Mutex) { lock.Lock() counter++ fmt.Println(z) lock.Unlock() } func main() { lock := &sync.Mutex{} for i := 0; i < 10; i++ { go Count(lock) } for { lock.Lock() c := counter lock.Unlock() runtime.Gosched() if c >= 10 { break } } }
The operation results are as follows:
# command-line-arguments ./main.go:14:14: undefined: z
Do not communicate through shared memory, but share memory through communication.
Channel
The code is as follows:
package main import ( "fmt" ) func Count(ch chan int) { ch <- 1 fmt.Println("Counting") } func main() { chs := make([]chan int, 10) for i := 0; i < 10; i++ { chs[i] = make(chan int) go Count(chs[i]) } for _, ch := range chs { <-ch } }
1. Basic grammar
The general declaration form of channel is:
var chanName chan ElementType
In the usage of channel, the most common include write and read.
The syntax of writing (sending) a data to the channel is very intuitive:
ch <- value
The syntax of reading data from channel is:
value:=<-ch
2,select
Go language directly supports the select keyword at the language level, which is used to deal with asynchronous I/O problems.
3. Buffer mechanism
4. Timeouts and timers
5. Transmission of channel
6. Unidirectional channel
7. Close channel
Use the close() function built in go language as follows:
close(ch)
Concurrent advanced
1. Multi core parallelization
2. Co process synchronization
The channel needs to be closed only when the receiver needs to be told that it will no longer provide new values.
Only the sender needs to close the channel, and the receiver will never need it.
The code is as follows:
package main import ( "fmt" "time" ) func sendData(ch chan string) { ch <- "New York" ch <- "Washington" ch <- "London" ch <- "Beijing" ch <- "Tokyo" } func getData(ch chan string) { var input string for { input = <-ch fmt.Printf("%s ", input) } } func main() { ch := make(chan string) go sendData(ch) go getData(ch) time.Sleep(1e9) }
The operation results are as follows:
New York Washington London Beijing Tokyo
The code is as follows:
package main import ( "fmt" ) func sendData(ch chan string) { ch <- "New York" ch <- "Washington" ch <- "London" ch <- "Beijing" ch <- "Tokyo" close(ch) } func getData(ch chan string) { for { input, open := <-ch if !open { break } fmt.Printf("%s ", input) } } func main() { ch := make(chan string) go sendData(ch) getData(ch) }
The operation results are as follows:
New York Washington London Beijing Tokyo