Atomic

概述 #

调用 sync/atomic 包即可。

错误的并发操作 #

先来看一个错误的示例。

通过启动 1000 个 goroutine 来模拟并发调用,在函数内部对变量 number 进行自增操作, 那么可能存在的一个问题是,当多个 goroutine 同时对变量操作时,只有一个成功了,其他的全部失败,造成的后果就是变量 最终的值小于 1000 (正常情况应该是等于 1000)。

package main

import (
	"fmt"
	"sync"
)

func main() {
	var number uint32
	var wg sync.WaitGroup

	for i := 0; i < 1000; i++ {
		wg.Add(1)

		go func() {
			defer func() {
				wg.Done()
			}()

			number++
		}()
	}

	wg.Wait()

	fmt.Printf("number = %d\n", number)
}

// $ go run main.go
// 输出如下,你的输出可能和这里的不一样,多试几次,会发现每次的结果都不一样
/**
  number = 971
*/

正确的并发操作 #

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

func main() {
	var number uint32
	var wg sync.WaitGroup

	for i := 0; i < 1000; i++ {
		wg.Add(1)

		go func() {
			defer func() {
				wg.Done()
			}()

			//number++
			atomic.AddUint32(&number, 1) // 使用原子操作
		}()
	}

	wg.Wait()

	fmt.Printf("number = %d\n", number)
}

// $ go run main.go
// 输出如下,多试几次,会发现结果都是一样的
/**
  number = 1000
*/

附录 #

使用 atomic 包对 uint32 类型实现 -1 功能 #

var value uint32
newValue := atomic.AddUint32(&value, 1)
t.Logf("new = %d", newValue)

atomic.AddUint32(&value, ^uint32(0))   // ^uint32(0) == -1
newValue = atomic.LoadUint32(&value)
t.Logf("new = %d", newValue)

转载申请

本作品采用 知识共享署名 4.0 国际许可协议 进行许可,转载时请注明原文链接,图片在使用时请保留全部内容,商业转载请联系作者获得授权。

© 蛮荆 | 陕公网安备 61011302001681 号 | 陕ICP备2023004378号-1 | Rendered by Hugo