最近想用go写一个报文统计功能,所以突发奇想先试一下直接对全局变量++,其是否是协程安全的。既然不明确,而且功能实现不复杂,干脆直接写一段代码验证一下。知行合一。代码如下:
package main
import (
"fmt"
"sync"
)
var gSum int = 0
var wg sync.WaitGroup
func main() {
for i := 0; i < 10000; i++ {
wg.Add(1)
go sum()
}
wg.Wait()
fmt.Println(gSum)
}
func sum() {
defer wg.Done()
gSum++
}
因为最后需要打印出来,这里的代码使用了waitgroup,每建立一个协程调用Add(1),每个协程执行完毕调用defer wg.Done(),而wg.Wait()将会等待10000次调用Done(),这样就可以保证所有协程均已退出。
结果
feiqianyousadeMacBook-Pro:go yousa$ ./plusplussafe
9085
feiqianyousadeMacBook-Pro:go yousa$ ./plusplussafe
8954
feiqianyousadeMacBook-Pro:go yousa$ ./plusplussafe
8940
feiqianyousadeMacBook-Pro:go yousa$ ./plusplussafe
8915
feiqianyousadeMacBook-Pro:go yousa$ ./plusplussafe
8955
feiqianyousadeMacBook-Pro:go yousa$ ./plusplussafe
9057
feiqianyousadeMacBook-Pro:go yousa$ ./plusplussafe
8880
feiqianyousadeMacBook-Pro:go yousa$ ./plusplussafe
8981
跑了几次结果基本都不一样,所以可以肯定,go的++操作并不是协程安全的
如果想使用协程安全的++,可以考虑sync/atomic包下的接口