GoLang之使用原子操作
注:本文基于Windos系统上Go SDK v1.18进行
1.原子操作性能比较
atomic包提供了底层的原子级内存操作,对于同步算法的实现很有用。这些函数必须谨慎地保证正确使用。除了某些特殊的底层应用,使用通道或者 sync 包的函数/类型实现同步更好。
我们填写一个示例来比较下互斥锁和原子操作的性能。
package main
import (
"fmt"
"sync"
"time"
)
type Counter interface {
Inc()
Load() int64
}
// 普通版
type CommonCounter struct {
counter int64
}
func (c CommonCounter) Inc() {
c.counter++
}
func (c CommonCounter) Load() int64 {
return c.counter
}
func test(c Counter) {
var wg sync.WaitGroup
start := time.Now()
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
c.Inc()
wg.Done()
}()
}
wg.Wait()
end := time.Now()
fmt.Println(c.Load(), end.Sub(start))
}
func main() {
c1 := CommonCounter{} // 非并发安全
//无论运行多少次,都输出以下结果
test(c1)//输出:0 2.0248ms
}
package main
import (
"fmt"
"sync"
"time"
)
type Counter interface {
Inc()
Load() int64
}
// 普通版
type CommonCounter struct {
counter int64
}
func (c *CommonCounter) Inc() {
c.counter++
}
func (c *CommonCounter) Load() int64 {
return c.counter
}
func test(c Counter) {
var wg sync.WaitGroup
start := time.Now()
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
c.Inc()
wg.Done()
}()
}
wg.Wait()
end := time.Now()
fmt.Println(c.Load(), end.Sub(start))
}
func main() {
c1 := CommonCounter{} // 非并发安全
test(&c1)
/*
第一次运行输出:991 1.9983ms
第二次运行输出:984 2.4997ms
*/
}
互斥锁版
package main
import (
"fmt"
"sync"
"time"
)
type Counter interface {
Inc()
Load() int64
}
// 互斥锁版
type MutexCounter struct {
counter int64
lock sync.Mutex
}
func (m *MutexCounter) Inc() {
m.lock.Lock()
defer m.lock.Unlock()
m.counter++
}
func (m *MutexCounter) Load() int64 {
m.lock.Lock()
defer m.lock.Unlock()
return m.counter
}
func test(c Counter) {
var wg sync.WaitGroup
start := time.Now()
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
c.Inc()
wg.Done()
}()
}
wg.Wait()
end := time.Now()
fmt.Println(c.Load(), end.Sub(start))
}
func main() {
c2 := MutexCounter{} // 使用互斥锁实现并发安全
test(&c2)//输出:1000 2.0023ms
}
原子操作版
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
)
type Counter interface {
Inc()
Load() int64
}
// 原子操作版
type AtomicCounter struct {
counter int64
}
func (a *AtomicCounter) Inc() {
atomic.AddInt64(&a.counter, 1)
}
func (a *AtomicCounter) Load() int64 {
return atomic.LoadInt64(&a.counter)
}
func test(c Counter) {
var wg sync.WaitGroup
start := time.Now()
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
c.Inc()
wg.Done()
}()
}
wg.Wait()
end := time.Now()
fmt.Println(c.Load(), end.Sub(start))
}
func main() {
c3 := AtomicCounter{} // 并发安全且比互斥锁效率更高
test(&c3)
//输出:1000 2.0003ms
}
2.使用
package main
import (
"fmt"
"sync/atomic"
)
func main() {
var a int32 = 4
//读取操作
fmt.Println(atomic.LoadInt32(&a)) //4
//写入操作
atomic.StoreInt32(&a, 5)
fmt.Println(a) //5
//修改操作
fmt.Println(atomic.AddInt32(&a, 6)) //11
//交换操作
fmt.Println(atomic.SwapInt32(&a, 20)) //11
fmt.Println(a) //20
//比较并交换操作
//成功
fmt.Println(atomic.CompareAndSwapInt32(&a, 20, 100)) //true
fmt.Println(a) //100
//失败
fmt.Println(atomic.CompareAndSwapInt32(&a, 99, 200)) //false
fmt.Println(a) //100
}