Golang map執行緒安全實現及sync.map使用及原理解析。

一把把把把住了發表於2020-12-25


前言

       眾所周知,Golang 的map是不安全的,所以sync包提供了執行緒安全的map。接下來就是把我對sync.map的理解寫出來分享給各位。


一、為什麼map執行緒不安全?

       map不是執行緒安全的。在同一時間段內,讓不同 goroutine 中的程式碼,對同一個字典進行讀寫操作是不安全的。字典值本身可能會因這些操作而產生混亂,相關的程式也可能會因此發生不可預知的問題。

二、配合(鎖)實現執行緒安全的map。

1.悲觀鎖的形式

悲觀鎖:進來的每一步操作都認為同時會有其他程式影響操作,所以提前加鎖。

lock.Lock()
//map的增刪改查操作
lock.UnLock()

2.樂觀鎖的形式

樂觀鎖:因為map執行緒不安全是同時:讀&&寫||寫&&寫 造成的,所以在map寫的時候加上鎖就會提高map的效能。

//查
lock.Lock()
//map的增刪改操作
lock.UnLock()

3.根據map實現原理,對小範圍進行加鎖。

另一種設想是在buckets層面加鎖,根據樂觀鎖的情況進行小範圍加鎖。
在這裡插入圖片描述

三、sync.map實現的原理。

1、sync.Map 的實現原理可概括為:

       過 read 和 dirty 兩個欄位將讀寫分離,讀的資料存在只讀欄位 read 上,將最新寫入的資料則存在 dirty 欄位上
       讀取時會先查詢 read,不存在再查詢 dirty,寫入時則只寫入 dirty
       讀取 read 並不需要加鎖,而讀或寫 dirty 都需要加鎖
       另外有 misses 欄位來統計 read 被穿透的次數(被穿透指需要讀 dirty 的情況),超過一定次數則將 dirty 資料同步到 read 上
       對於刪除資料則直接通過標記來延遲刪除

2、sync.Map 使用方法:

	var ma sync.Map// 該型別是開箱即用,只需要宣告既可
    ma.Store("key", "value") // 儲存值
    ma.Delete("key") //刪除值
    ma.LoadOrStore("key", "value")// 獲取值,如果沒有則儲存
    fmt.Println(ma.Load("key"))//獲取值
    
    //遍歷
    ma.Range(func(key, value interface{}) bool {
        fmt.Printf("key:%s ,value:%s \n", key, value)
        //如果返回:false,則退出迴圈,
        return true
    })


總結

        map底層雖然寫的尤為漂亮,但是為了效率,沒有吧執行緒安全安排上,所以另外加了sync.map,相容執行緒安全。在我的理解中,sync.map實現就是依靠兩張map對讀操作和寫操作分離,後續根據需要在把dirty map合入 read map中。相對於樂觀鎖實現的方式,寫程式執行的時候,讀程式也可能在read map上進行。
        如有問題請聯絡本人指正,謝謝~

相關文章