1. 程式人生 > 其它 >Golang sync/atomic包——原子操作

Golang sync/atomic包——原子操作

1、概述

1.1 基本概念

原子性:一個或多個操作在CPU的執行過程中不被中斷的特性,稱為原子性。這些操作對外表現成一個不可分割的整體,他們要麼都執行,要麼都不執行,外界不會看到他們只執行到一半的狀態。

原子操作:進行過程中不能被中斷的操作,原子操作由底層硬體支援,而鎖則是由作業系統提供的API實現,若實現相同的功能,前者通常會更有效率

Golang 中的原子操作:sync/atomic包

能夠進行原子操作的型別:int32, int64, uint32, uint64, uintptr, unsafe.Pointer

五種操作函式:增或減、比較並交換、載入、儲存、交換

原子操作比鎖更為高效。

1.2 原子操作 vs 鎖

  • 加鎖比較耗時,需要上下文切換。即使是goroutine也需要上下文切換
  • 只針對基本型別,可使用原子操作保證執行緒安全
  • 原子操作在使用者態完成,效能比互斥鎖要高
  • 原子操作步驟簡單,不需要加鎖-操作-解鎖

1.3 五種操作

  • 增或減 (Add)
  • 比較並交換 (CAS, Compare & Swap)
  • 載入 (Load)
  • 儲存 (Store)
  • 交換 (Swap)

1.4 最小案例

package main

import (
	"sync"
	"fmt"
)

var count int

func add(wg *sync.WaitGroup) {
	defer wg.Done()
	count++
}

func main() {
	wg := sync.WaitGroup{}
	wg.Add(1000)
	for i := 0; i < 1000; i++ {
		go add(&wg)
	}
	wg.Wait()
	fmt.Println(count)
}

count不會等於1000,因為count++這一步實際是三個操作:

  • 從記憶體讀取count
  • CPU更新count = count + 1
  • 寫入count到記憶體

因此就會出現多個goroutine讀取到相同的數值,然後更新同樣的數值到記憶體,導致最終結果比預期少。

2、sync/atomic包使用

Go語言提供的原子操作都是非入侵式的,由標準庫中sync/aotomic中的眾多函式代表

atomic包中支援六種型別

  • int32
  • uint32
  • int64
  • uint64
  • uintptr
  • unsafe.Pointer

對於每一種型別,提供了五類原子操作:

  • LoadXXX(addr): 原子性的獲取*addr
    的值,等價於:
    return *addr
  • StoreXXX(addr, val): 原子性的將val的值儲存到*addr,等價於:
    addr = val
  • AddXXX(addr, delta): 原子性的將delta的值新增到*addr並返回新值(unsafe.Pointer不支援),等價於:
    *addr += delta
    return *addr
  • SwapXXX(addr, new) old: 原子性的將new的值儲存到*addr並返回舊值,等價於:
    old = *addr
    *addr = new
    return old
  • CompareAndSwapXXX(addr, old, new) bool: 原子性的比較*addrold,如果相同則將new賦值給*addr並返回true,等價於:
    if *addr == old {
        *addr = new
        return true
    }
    return false

因此第一部分的案例可以修改如下,即可通過

// 修改方式1
func add(wg *sync.WaitGroup) {
	defer wg.Done()
	atomic.AddInt32(&count, 1)
}

// 修改方式2
func add(wg *sync.WaitGroup) {
	defer wg.Done()
	for {
		if atomic.CompareAndSwapInt32(&count, count, count+1) {
			break
		}
	}
}

參考:https://juejin.cn/post/6844904053042839560

參考:https://blog.csdn.net/elihe2011/article/details/109157797