Facing goroutines, we all need to wait for it to complete what is given to it, wait for it to complete calculation or execution, so we have to use() to sleep for a while where the program needs to wait, and wait for other goroytines to be executed. The following code prints 1 to 100 for the for loop that can be run in a very fast time, but we must add() to wait for it to complete printing, if we don't wait, it seems that nothing has happened. . . . . This is certainly not what we want!
func main(){ for i := 0; i < 100 ; i++{ go (i) } () }
This is the stupid way I first learned goroutine. . . . Wait until death! Can't wait *2 Can't wait *3
However, for our actual usage scenarios, the waiting time of 1 second may be a bit long, and sometimes it is far from enough. The most important thing is that we cannot predict the running time of gorotine, so we cannot specify the time for Sleep to sleep.
I just learned channel a few days ago, so now we can
Use channel to achieve our goal
func main() { c := make(chan bool, 100) for i := 0; i < 100; i++ { go func(i int) { (i) c <- true }(i) } for i := 0; i < 100; i++ { <-c } }
Perfect output! Here we can see our wins from the console, but we have a better way of dealing with it:
There is a counter inside the WaitGroup object, which initially starts from 0, and it has three methods: Add() Done() Wait() is used to control the number of counters to achieve the purpose of waiting.
func main() { wg := {} (100) for i := 0; i < 100; i++ { go func(i int) { defer () (i) }(i) } () }
First use add(100) to set the number of counters to 100. Each cycle is completed and the counter is reduced by 1. The main function uses Wait()
Block until the counter ends with 0 and ends with the main thread.
The main thread will be blocked here! ! ! Need to pay attention.
In addition: the numbers printed in the above three methods are all disordered
type WaitGroup struct { noCopy noCopy state1 [3]uint32 }
It's just a struct so when the parameter is passed, you need to pass a pointer.
Supplementary: Error usage and correction
This article mainly records the errors caused by pointers during the learning golang language and the errors caused by pointers.
1. Incorrect usage scenario
The main package implementation content:
package main import ( "fmt" "pressure/game" "sync" ) var waitGroup //Define a group that waits synchronouslyfunc main(){ (1) //Add a count go (serverAddr, waitGroup) //Calling other package methods to execute tasks () //Block until all tasks are completed ("main DONE!!!") }
The following is the content of the game package:
package game import ( "fmt" "net" "strconv" "strings" "sync" ) var gameWait func ConnSocket(serverAddr string, wait ) { var err error Conn, err = ("tcp", serverAddr) if err != nil { ("Error connected:", ()) () return } gameWait = wait ("connected OK:", ()) go readMessage() } func readMessage() { ("readMessage:") for { if OK:=dosomething(),OK{ () } } }
Then execute the above code and an error will occur:
panic: sync: negative WaitGroup counter
goroutine 12 [running]:
sync.(*WaitGroup).Add(0x7b8b90, 0xffffffffffffffff)
D:/Program Files/Go/src/sync/:75 +0x1d0
sync.(*WaitGroup).Done(0x7b8b90)
reason:
func ConnSocket(serverAddr string, wait ) just passes the value over, not the memory address, so when assigning to gameWait, it is just assigning a value. gameWait does not point to the memory address of waitGroup in main, resulting in the count 1 in main not being obtained at (), so it will report a negative number. The reason is that there is no understanding of pointers. So the above problem has been modified.
2. Correct use
The main package implementation content:
package main import ( "fmt" "pressure/game" "sync" ) var waitGroup //Define a group that waits synchronouslyfunc main(){ (1) //Add a count //The memory address of waitGroup is passed here go (serverAddr, &waitGroup) //Calling other package methods to execute tasks () //Block until all tasks are completed ("main DONE!!!") }
The following is the content of the game package:
package game import ( "fmt" "net" "strconv" "strings" "sync" ) var gameWait *//It is also declared as a pointer variable//Pass parameters are passed as pointers*, that is, wait points to the memory address of waitGroup in mainfunc ConnSocket(serverAddr string, wait *) { var err error Conn, err = ("tcp", serverAddr) if err != nil { ("Error connected:", ()) () return } gameWait = wait//The pointer points to another pointer, so gameWait points to the address of wait, so gameWait modifys wait memory address and the value of the latch will also change as well. ("connected OK:", ()) go readMessage() } func readMessage() { ("readMessage:") for { if OK:=dosomething(),OK{ () } } }
3. Results
This problem occurs if you don’t have a thorough understanding of pointer transfer and value transfer, so you need to learn and understand more about pointers. In case similar problems occur in future work.
The above is personal experience. I hope you can give you a reference and I hope you can support me more. If there are any mistakes or no complete considerations, I would like to give you advice.