Go并发原语
协程Goroutines
每个go程序至少都有一个Goroutine:主Goroutine(在运行进程时自动创建)。以及程序中其他Goroutine 例如:下面程序创建了main的Goroutine及匿名的Goroutine。
func main() {
go func() {
fmt.Println("you forgot me !")
}()
}
WaitGroup
假设主线程要等待其余的goroutine都运行完毕,不得不在末尾添加time.Sleep(),但是这样会引发两个问题:
等待多长时间?
时间太长,影响性能?
在go的sync库中的WaitGroup可以帮助我们完成此项工作,Add(n)把计数器设置为n,Done()会将计数器每次减1,Wait()函数会阻塞代码运行,直到计数器减0。
等待多个goroutine完成,可以使用一个等待组。 例如:
// 这是我们将在每个goroutine中运行的函数。
// 注意,等待组必须通过指针传递给函数。
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second)
fmt.Printf("Worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait()
}
这里首先把wg 计数设置为1, 每个for循环运行完毕都把计数器减一,主函数中使用Wait() 一直阻塞,直到wg为1——也就是所有的5个for循环都运行完毕。
使用注意点:
计数器不能为负值
WaitGroup对象不是引用类型
Once
sync.Once可以控制函数只能被调用一次,不能多次重复调用。
var doOnce sync.Once
func main() {
DoSomething()
DoSomething()
}
func DoSomething() {
doOnce.Do(func() {
fmt.Println("Run once - first time, loading...")
})
fmt.Println("Run this every ti