面临的挑战
- 字段类型限制:
atomic
包主要支持基础类型(如int32
、int64
、uintptr
和指针类型)的原子操作。对于结构体中的非上述类型字段,无法直接使用atomic
包进行原子操作。例如结构体中包含float64
、自定义结构体等,无法直接原子化。
- 整体原子性:即使结构体中部分字段类型可以使用
atomic
操作,要保证整个结构体作为一个整体的原子性访问是困难的。比如结构体有多个字段,对其中一个字段的原子更新,可能导致其他相关字段处于不一致状态,而atomic
包没有直接提供整体结构体原子更新的方法。
- 缓存一致性:在多核系统中,
atomic
操作依赖缓存一致性协议。复杂结构体的多个字段分布在不同缓存行,对不同字段的原子操作可能引发缓存行迁移和同步开销,影响性能。
基于atomic
包现有功能的解决方案
- 字段拆分与原子化:对于结构体中支持
atomic
操作的字段,分别使用atomic
包的相应函数进行操作。例如,结构体中有int32
类型字段count
,可以使用atomic.AddInt32
等函数来保证count
的并发安全。
package main
import (
"fmt"
"sync"
"sync/atomic"
)
type MyStruct struct {
count int32
// 其他字段
}
func main() {
var wg sync.WaitGroup
var ms MyStruct
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
atomic.AddInt32(&ms.count, 1)
}()
}
wg.Wait()
fmt.Println("Final count:", atomic.LoadInt32(&ms.count))
}
- 指针原子操作与结构体整体更新:将整个结构体作为指针类型处理,使用
atomic.CompareAndSwapPointer
等函数来实现结构体整体的原子更新。先创建一个新的结构体实例,准备好所有更新后,通过原子比较并交换指针,保证整体更新的原子性。
package main
import (
"fmt"
"sync"
"sync/atomic"
)
type InnerStruct struct {
value int
}
type OuterStruct struct {
inner InnerStruct
// 其他字段
}
func main() {
var wg sync.WaitGroup
var osPtr *OuterStruct
initialOS := &OuterStruct{InnerStruct{0}}
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&osPtr)), unsafe.Pointer(initialOS))
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
oldPtr := atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&osPtr)))
oldOS := (*OuterStruct)(oldPtr)
newInner := InnerStruct{oldOS.inner.value + 1}
newOS := &OuterStruct{newInner}
if atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&osPtr)), oldPtr, unsafe.Pointer(newOS)) {
break
}
}
}()
}
wg.Wait()
finalOS := (*OuterStruct)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&osPtr))))
fmt.Println("Final inner value:", finalOS.inner.value)
}
- 互斥锁辅助:对于不支持
atomic
操作的字段,可以结合sync.Mutex
来保证并发安全。在结构体中嵌入一个sync.Mutex
,在访问和修改不支持原子操作的字段时,先获取锁。
package main
import (
"fmt"
"sync"
)
type MyComplexStruct struct {
sync.Mutex
nonAtomicField float64
// 其他字段
}
func main() {
var wg sync.WaitGroup
var mcs MyComplexStruct
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mcs.Lock()
mcs.nonAtomicField += 1.0
mcs.Unlock()
}()
}
wg.Wait()
mcs.Lock()
fmt.Println("Final non - atomic field value:", mcs.nonAtomicField)
mcs.Unlock()
}