Q & A in the previous section
In the previous section, a reader asked how big the goroutine stack size is. I made a detailed query
About goroutine stack size Official documents As described in, the minimum is 4kb before 1.2, becomes 8kb at 1.2, and can be used SetMaxStack Set the maximum stack size.
stay runtime/debug The package can control the stack size of the largest single goroutine. The default is 1GB on 64 bit systems and 250MB on 32-bit systems.
Because each goroutine needs to be able to run, they have their own stack. If each goroutine allocates a fixed stack size and cannot grow, too small will lead to overflow, too large will waste space, and many goroutines cannot exist.
So in Version 1.3 In, change to continuous stack( Continuous stack ), in order to solve this problem, goroutine can initially allocate only a small space (8KB) to the stack, and then automatically grow as needed in the process of use. This is why Go can open thousands of goroutines without running out of memory.
Version 1.4 goroutine stack reduced from 8Kb to 2Kb
Golang concurrent wait
Source location of this section https://github.com/golang-minibear2333/golang/blob/master/4.concurrent/goroutine-wait/
brief introduction
Goroutine is a very useful function in Golang. Sometimes goroutine returns before it finishes executing the function. What should I do if I want to wait for the current goroutine to finish executing and then proceed?
func say(s string) { for i := 0; i < 3; i++ { time.Sleep(100 * time.Millisecond) fmt.Println(s) } } func main() { go say("hello world") fmt.Println("over!") }
Output over, The main thread is not waiting
Use Sleep to wait
func main() { go say("hello world") time.Sleep(time.Second*1) fmt.Println("over!") }
Run the modified program and the results are as follows:
hello world hello world hello world over!
The result is as expected, but it is too low. We don't know how long we should wait in the actual implementation, so we can't accept this scheme!
Send signal
func main() { done := make(chan bool) go func() { for i := 0; i < 3; i++ { time.Sleep(100 * time.Millisecond) fmt.Println("hello world") } done <- true }() <-done fmt.Println("over!") }
The output results are the same as above and meet expectations
This method cannot handle multiple processes, so it is not an elegant solution.
WaitGroup
Golang officially provides WaitGroup type in sync package to solve this problem. The document description is as follows:
The usage methods can be summarized as follows:
- Create a WaitGroup instance in the parent collaboration, for example, with the name: wg
- Call WG Add (n), where n is the number of goroutine s waiting
- Execute defer WG in each function that goroutine runs Done()
- Call WG Wait() blocks the main logic
- Until all goroutine execution is completed.
func main() { var wg sync.WaitGroup wg.Add(2) go say2("hello", &wg) go say2("world", &wg) fmt.Println("over!") wg.Wait() } func say2(s string, waitGroup *sync.WaitGroup) { defer waitGroup.Done() for i := 0; i < 3; i++ { fmt.Println(s) } }
Output, note that the order is chaotic because of concurrent execution
hello hello hello over! world world world
Beware of defects
For a short example, note that the variables passed in by the loop are replaced by intermediate variables to prevent closure bug s
func errFunc() { var wg sync.WaitGroup sList := []string{"a", "b"} wg.Add(len(sList)) for _, d := range sList { go func() { defer wg.Done() fmt.Println(d) }() } wg.Wait() }
Output, you can find that all become the last one
b b
The parent and child processes are concurrent. The for loop on the parent coroutine is executed instantaneously, and the internal coroutine uses the last value of d, which is the closure problem.
The solution is passed in as a parameter
func correctFunc() { var wg sync.WaitGroup sList := []string{"a", "b"} wg.Add(len(sList)) for _, d := range sList { go func(str string) { defer wg.Done() fmt.Println(str) }(d) } wg.Wait() }
output
b a
Note that the value in range may have a pit that may be encountered in 1.7.3! (in e-book golang.coding3min.com)
quote
Getting started with Golang: wait for goroutine to complete the task