Go語言——sync.Map原始碼分析

w1015357065發表於2020-01-03

點選這裡,檢視更具體原理,優化點,方法原始碼分析等更多重要內容

簡介: 眾所周知,go 普通的 map 是不支援併發的,換而言之,不是執行緒 (goroutine) 安全的。博主是從 golang 1.4 開始使用的,那時候 map 的併發讀是沒有支援,但是併發寫會出現髒資料。


golang 1.6 之後,併發地讀寫會直接 panic:

fatal error: concurrent map read and map write
package main
func main() {
    m := make(map[int]int)
    go func() {
        for {
            _ = m[1]
        }
    }()
    go func() {
        for {
            m[2] = 2
        }
    }()
    select {}
}

所以需要支援對 map 的併發讀寫時候,博主使用兩種方法:
1、 第三方類庫 concurrent-map。
2、 map 加上 sync.RWMutex 來保障執行緒 (goroutine) 安全的。

golang 1.9 之後,go 在 sync 包下引入了併發安全的 map,也為博主提供了第三種方法。本文重點也在此,為了時效性,本文基於 golang 1.10 原始碼進行分析。

sync.Map

結構體

Map

type Map struct {
    mu Mutex    //互斥鎖,用於鎖定dirty map

read atomic.Value //優先讀map,支援原子操作,註釋中有readOnly不是說read是隻讀,而是它的結構體。read實際上有寫的操作

dirty map[interface{}]*entry // dirty是一個當前最新的map,允許讀寫

misses int // 主要記錄read讀取不到資料加鎖讀取read map以及dirty map的次數,當misses等於dirty的長度時,會將dirty複製到read }

readOnly

readOnly 主要用於儲存,通過原子操作儲存在 Map.read 中元素。

type readOnly struct {
    m       map[interface{}]*entry
    amended bool // 如果資料在dirty中但沒有在read中,該值為true,作為修改標識
}

entry

type entry struct {
    // nil: 表示為被刪除,呼叫Delete()可以將read map中的元素置為nil
    // expunged: 也是表示被刪除,但是該鍵只在read而沒有在dirty中,這種情況出現在將read複製到dirty中,即複製的過程會先將nil標記為expunged,然後不將其複製到dirty
    //  其他: 表示存著真正的資料
    p unsafe.Pointer // *interface{}
}

原理


關鍵字: Go  原始碼分析

更多原創文章乾貨分享,請關注公眾號
  • Go語言——sync.Map原始碼分析
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章