sync/atomic包提供了原子操作的能力,直接有底层CPU硬件支持,因而一般要比基于操作系统API的锁方式效率高些;
这些功能需要非常小心才能正确使用。 除特殊的底层应用程序外,同步更适合使用channel或sync包的功能。 通过消息共享内存; 不要通过共享内存进行通信。
原子增值
我们通过下面用例来了解下,原子增值跟普通增值的不同
package main
import (
"fmt"
"sync/atomic"
"sync"
)
func main() {
var sum uint32 = 200
var wg sync.WaitGroup
for i:=0; i< 30; i++ {
wg.Add(1)
go func() {
defer wg.Done()
atomic.AddUint32(&sum, 1)
}()
}
wg.Wait()
fmt.Println(sum)
for i:=0; i< 30; i++ {
wg.Add(1)
go func() {
defer wg.Done()
sum++
}()
}
wg.Wait()
fmt.Println(sum)
}
将上面程序在工作机上编译,然后运行几次,你会发现第一个打印值固定不变,第二个值不固定
CAS(Compare-And-Swap)比较并交换
func CompareAndSwapInt32(addr *int32, old, newint32) (swappedbool)
下面代码体现了三种情况:
a.当addr地址指向变量的值不等于old
b.当addr地址指向变量的值等于old,等于new
c.当addr地址指向的变量值等于old,不等于new
import (
"fmt"
"sync/atomic"
"sync"
)
func main() {
sum := uint32(10)
rst := false
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
rst = atomic.CompareAndSwapUint32(&sum, 100, 200)
}()
}
wg.Wait()
fmt.Println(sum)
fmt.Println(rst)
rst1 := false
sum1 := uint32(100)
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
rst1 = atomic.CompareAndSwapUint32(&sum1, 100, 100)
}()
}
wg.Wait()
fmt.Println(sum1)
fmt.Println(rst1)
rst2 := false
sum2 := uint32(100)
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
rst2 = atomic.CompareAndSwapUint32(&sum2, 100, 200)
}()
}
wg.Wait()
fmt.Println(sum2)
fmt.Println(rst2)
}
运行结果:
10
false
100
true
200
false
原子导出值
package main
import (
"fmt"
"sync/atomic"
"sync"
)
func main() {
sum := uint32(1020)
rst := uint32(0)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
rst = sum
}()
}
wg.Wait()
fmt.Println(sum)
fmt.Println(rst)
}
原子导入值
package main
import (
"fmt"
"sync/atomic"
"sync"
)
func main() {
rst := uint32(0)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
atomic.StoreUint32(&rst, 160)
}()
}
wg.Wait()
fmt.Println(rst)
}
原子交互
package main
import (
"fmt"
"sync/atomic"
"sync"
)
func main() {
rst := uint32(0)
old := uint32(0)
old = atomic.SwapUint32(&rst, 1234)
fmt.Println(rst)
fmt.Println(old)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
old = atomic.SwapUint32(&rst, 1234)
}()
}
wg.Wait()
fmt.Println(rst)
fmt.Println(old)
}
运行结果
1234
0
1234
1234