为什么要有协程同步?
| func main() { go func() { fmt.Println("goroutine 1") }() go func() { fmt.Println("goroutine 2") }() } |
执行以上代码块,发现没有打印结果,原因就是主协程main在goroutine 1和goroutine 2执行之前已经先行结束,协程没有同步。
1.让主协程休息一段时间,等待其他协程执行完成后再结束| func main() { go func() { fmt.Println("goroutine 1") }() go func() { fmt.Println("goroutine 2") }() time.Sleep(time.Second) } |
缺点是不知道需要等待多长时间
2.channel| func main() { ch := make(chan struct{}) go func() { fmt.Println("goroutine 1") ch <- struct{}{} }() go func() { fmt.Println("goroutine 2") ch <- struct{}{} }() <-ch <-ch } |
channel和goroutine是分不开的,搭配干活不累。
3.sync.WaitGroupAdd() 用来添加计数Done() 用来在操作结束时调用,使计数减一Wait() 用来等待所有的操作结束,即计数变为 0,该函数会在计数不为 0 时等待,在计数为 0 时立即返回
| func main() { var wg sync.WaitGroup wg.Add(2) go func() { fmt.Println("goroutine 1") wg.Done() }() go func() { fmt.Println("goroutine 2") wg.Done() }() wg.Wait() } |
关于WaitGroup源码如下:
| // A WaitGroup waits for a collection of goroutines to finish. // The main goroutine calls Add to set the number of // goroutines to wait for. Then each of the goroutines // runs and calls Done when finished. At the same time, // Wait can be used to block until all goroutines have finished. // // A WaitGroup must not be copied after first use. type WaitGroup struct { noCopy noCopy // 64-bit value: high 32 bits are counter, low 32 bits are waiter count. // 64-bit atomic operations require 64-bit alignment, but 32-bit // compilers do not ensure it. So we allocate 12 bytes and then use // the aligned 8 bytes in them as state, and the other 4 as storage // for the sema. state1 [3]uint32 } |
一个WaitGroup等待多个goroutine执行完成,main的goroutine可以调用Add()方法设置需要等待的goroutine数量,之后每一个goroutine在运行结束时调用Done(),在这段时间内,我们可以使用Wait()阻塞main的goroutine直到所有的goroutine都执行完成,WaitGroup不能进行复制操作【struct里面有noCopy类型,禁止做值拷贝,只能通过指针来传递】



