Golang并发编程-atomic原子操作包详解

1 关于atomic包

atomic包位于sync目录下。它提供了低级原子内存原语,用于实现同步算法。

这些函数需要非常小心地使用才能正确地工作。
除非是特殊的、低级的应用程序,否则最好使用通道或[sync]包来进行同步:通过通信共享内存;不要通过共享内存进行通信

上面这段注释是源码中的注释,尽管推荐使用通道或[sync]包来进行同步,但atomic包仍然具有一些优势和适用场景,包括:

  • 原子性操作:atomic包提供了一些原子性操作,如Swap、Add和CompareAndSwap等,能够在不需要锁的情况下进行原子性操作,避免了竞态条件。
  • 内存模型:atomic操作遵循Go内存模型的规范,保证了在不同goroutines之间的内存同步和一致性。
  • 性能:相比使用锁和通道进行同步,atomic操作通常具有更低的开销和更高的性能,特别是在需要频繁进行原子性操作的情况下。
  • 低级控制:atomic包提供了对内存的低级原子操作,允许开发者更精细地控制并发程序的同步和状态管理。
  • 特定场景:在特定的性能要求和同步需求下,atomic操作可以是更合适的选择,特别是在需要对共享内存进行细粒度的原子操作时。

2 atomic包中的类型

atomic包中定义了如下几个类型:

  • Bool:表示原子的布尔类型,零值为false
  • Int32:表示原子的int32类型,零值为0
  • Int64:表示原子的int64类型,零值为0
  • Uint32:表示原子的uint32类型,零值为0
  • Uint64:表示原子的uint64类型,零值为0
  • Pointer:表示T (泛型)类型的原子指针。零值是 nil T。
  • Uintptr:表示原子的uintptr类型,零值为0
  • Value:Value 提供一致类型值的原子加载和存储。 Value 的零值从 Load 返回 nil。一旦 Store 被调用,Value 就不能被复制。

3 atomic包中的方法

atomic包提供了一系列原子操作方法:

  • Load : 原子地加载并返回存储的值
  • Store:原子地存储值
  • Add:原子地加上一个增量,并返回新的值。
  • Swap:原子地存储新值,并返回旧值。
  • CompareAndSwap:原子地进行比较和交换操作:
    • 如果原值与指定值(第一个参数)相等,就存储新值(第二个参数),并返回true。
    • 如果原值与指定值(第一个参数)不相等,直接返回false。

上述的方法,除了Add方法只支持Int32、Int64、Uint32、Uint64、Uintptr外,其他四个方法支持章节2中的所有类型。

4 使用示例

4.1 使用Int64实现线程安全的计算

先看一个线程不安全的实现:

func main() {
	startTime := time.Now()
	waitGroup := sync.WaitGroup{}
	for i := 0; i < 10; i++ {
		waitGroup.Add(1)
		go func() {
			defer waitGroup.Done()
			Add(int64(i))
		}()
	}
	waitGroup.Wait()
	fmt.Println(num)
	fmt.Printf("use time:%dms", time.Now().Sub(startTime)/time.Millisecond)
}

func Add(x int64) {
	for i := 0; i < 1000000; i++ {
		num = num + x
	}
}

多次执行这段代码会发现,执行结果不唯一,且大部分时候是小于期望的结果:45000000的。将上述的代码改造成使用atomic.Int64:

func main() {
	startTime := time.Now()
	waitGroup := sync.WaitGroup{}
	for i := 0; i < 10; i++ {
		waitGroup.Add(1)
		go func() {
			defer waitGroup.Done()
			Add(int64(i))
		}()
	}
	waitGroup.Wait()
	fmt.Println(num.Load())
	fmt.Printf("use time:%dms", time.Now().Sub(startTime)/time.Millisecond)
}

func Add(x int64) {
	for i := 0; i < 1000000; i++ {
		num.Add(x)
	}
}

执行改造后的代码可以发现,每次都能得到期望结果:45000000.

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值