This is a creation in Article, where the information may have evolved or changed.
Go programming Language: Support concurrent, garbage collection of compiled system-level programming language! The go language supports concurrency on a language level, unlike other languages, unlike when we used the thread library to create new threads and share data with thread-safe queue libraries.
One, concurrent concurrency
1. Basic Concepts
The fundamental reason that go can handle high concurrency is that the go process requires very little stack memory (presumably 4~5kb) and can dynamically grow and shrink the resources that are consumed as needed.
Go high concurrency is actually implemented by Goroutine, Goroutine is the official implementation of the Super "thread pool."
In simple terms, goroutine is a piece of code, a function entry, and a stack allocated to it on the heap. So it's very cheap, we can easily create tens of thousands of goroutine, but they are not being dispatched by the operating system, but through the system's threads to dispatch the execution of these functions, so that each go function executed with the keyword can be run as a unit of the process. When a co-process is blocked, the scheduler automatically arranges the other threads to execute in another thread, thus enabling the program to run without waiting for parallelism. And the scheduling overhead is very small, the size of a CPU scheduling is not more than million per second, which makes it possible to create a large number of goroutine in the program, high concurrency, while still maintaining high performance.
Goroutine 奉行通过通信来共享内存,而不是共享内存来通信。
2. Differentiate concurrency and parallelism
Here relates to a problem, many students do not know the difference between concurrency and parallelism, here I based on my knowledge of the problem of a Netizen's example, I feel very good:
- You eat half of the meal, the phone is coming, you have been to eat until after the pick up, which means that you do not support concurrency and do not support parallel
- You eat half of the meal, the phone came, you stopped to pick up the phone, and then continue to eat, which shows that you support concurrent
- You eat half of the meal, the phone is coming, you are on the phone while eating, it shows that you support parallel
Concurrency :你有处理多个任务的能力,不一定同时(一个CPU轮流)
Parallel :有同时处理多个任务的能力(多个CPU同时)
Both concurrency and parallelism can be a lot of threads, just look at这些线程能不能同时被(多个)CPU执行,可以说明是并行,并发是多个线程被一个CPU轮流切换着执行。
Concurrency not parallel: Concurrency is not Parallelism
Concurrency is mainly by switching time slices to achieve "simultaneous" operation, while parallel is the direct use of multi-core implementation of multi-threaded operation, but go can set the use of the number of cores to play a multi-core computer capabilities.
concurrency, because the CPU executes too fast, and constantly switching back and forth, so that people think it is at the same time.
Concurrency is better than parallelism, making full use of the CPU.
3. Channel Channels
Channelis a goroutine bridge of communication, mostly blocking the synchronization of
- by
make creating, close closing
- Channel is a reference type
- Can be used
for range to iterate the channel continuously
- One-way or two-way channels can be set
- Cache size can be set without blocking until it is filled
4.Select
- Can handle the sending and receiving of one or more channel
- At the same time there are multiple available channel at random sorting processing
- Free Select to block the main function
- can set timeout
Second, the concurrency example
1. Not using the Channel keyword
package mainimport ( "fmt" "time") func main() { go Go() // 使用go关键字就可执行goroutine time.Sleep(2 * time.Second) fmt.Println("Hey ...!")}func Go() { fmt.Println("Go ...!") }
Print:
➜ src go run myfirstgo/concurrency.goGo ...!Hey ...!
2. Using the Channel keyword
package mainimport ( "fmt") func main() { // 创建channel c := make(chan bool) // 执行到此处会阻塞 go func() { fmt.Println("Go ...!") c <- true }() // 将true的东西存到channel当中,然后读出来结束运行,即通知main函数,我这里运行完成了,可以结束了 <-c fmt.Println("Hey ...!")}
Print:
➜ src go run myfirstgo/concurrency.goGo ...!Hey ...!
3.range Example
func main() { // 创建channel c := make(chan bool) // 执行到此处会阻塞 go func() { fmt.Println("Go ...!") c <- true close(c) }() for v := range c { fmt.Println(v) } fmt.Println("Hey ...!")}
Print:
➜ src go run myfirstgo/concurrency.goGo ...!trueHey ...!
4. Multi-core
package mainimport ( "fmt" "runtime") // 当使用单线程执行时,会按部就班,按照顺序1,2,3,4执行下去// 当使用多个CPU核数时,任务分配是不定的,func main() { // 使用多核 runtime.GOMAXPROCS(runtime.NumCPU()) c := make(chan bool, 10) for i := 0; i < 10; i++ { go Go(c, i) } <-c}func Go(c chan bool, index int) { a := 1 for i := 0; i < 100000000; i++ { a += i } fmt.Println(index, a) if index == 9 { c <- true }}
Run Multiple execution results:
➜ src go run myfirstgo/concurrency.go3 49999999500000010 49999999500000011 49999999500000019 4999999950000001➜ src go run myfirstgo/concurrency.go2 49999999500000011 49999999500000013 49999999500000019 4999999950000001➜ src go run myfirstgo/concurrency.go9 4999999950000001➜ src go run myfirstgo/concurrency.go2 49999999500000019 4999999950000001
When multiple CPU cores (Runtime.gomaxprocs) are used, the task assignment is variable, so the top result appears.
There are two types of solutions:
The first type:
Set a channel with a cache length of 10
package mainimport ( "fmt" "runtime") // 当使用单线程执行时,会按部就班,按照顺序1,2,3,4执行下去// 当使用多个CPU核数时,任务分配是不定的,func main() { // 使用多核 runtime.GOMAXPROCS(runtime.NumCPU()) c := make(chan bool, 10) for i := 0; i < 10; i++ { go Go(c, i) } // 设置一个缓存长度为10 的channel for i := 0; i < 10; i++ { <-c } }func Go(c chan bool, index int) { a := 1 for i := 0; i < 100000000; i++ { a += i } fmt.Println(index, a) c <- true}
Print:
➜ src go run myfirstgo/concurrency.go1 49999999500000012 49999999500000019 49999999500000013 49999999500000017 49999999500000010 49999999500000018 49999999500000016 49999999500000014 49999999500000015 4999999950000001➜ src go run myfirstgo/concurrency.go0 49999999500000019 49999999500000015 49999999500000011 49999999500000017 49999999500000012 49999999500000018 49999999500000013 49999999500000016 49999999500000014 4999999950000001
The second type:
Not through the channel solution, but through sync the package to solve, it has a waitGroup , can create a task group, you can add tasks, each completed a task, the mark is complete Done , the main function is to determine whether all the tasks are completed, if all completed, Exit the program.
package mainimport ( "fmt" "runtime" "sync") // 当使用单线程执行时,会按部就班,按照顺序1,2,3,4执行下去// 当使用多个CPU核数时,任务分配是不定的,func main() { // 使用多核 runtime.GOMAXPROCS(runtime.NumCPU()) // sync wg := sync.WaitGroup{} wg.Add(10) for i := 0; i < 10; i++ { go Go(&wg, i) } wg.Wait() }func Go(wg *sync.WaitGroup, index int) { a := 1 for i := 0; i < 100000000; i++ { a += i } fmt.Println(index, a) wg.Done()}
Print:
➜ src go run myfirstgo/concurrency.go1 49999999500000015 49999999500000017 49999999500000019 49999999500000016 49999999500000018 49999999500000010 49999999500000012 49999999500000013 49999999500000014 4999999950000001➜ src go run myfirstgo/concurrency.go1 49999999500000019 49999999500000012 49999999500000013 49999999500000014 49999999500000015 49999999500000010 49999999500000016 49999999500000017 49999999500000018 4999999950000001
Related articles:
Golang language concurrency and a detailed understanding of parallel--goroutine and channel (i)
Goroutine scheduling mechanism of Golang