Zlib是一個開源的數據壓縮庫,提供了一種通用的數據壓縮和解壓縮演算法。它最初由Jean-Loup Gailly和Mark Adler開發,旨在成為一個高效、輕量級的壓縮庫,其被廣泛應用於許多領域,包括網路通信、文件壓縮、資料庫系統等。其壓縮演算法是基於DEFLATE演算法,這是一種無損數據壓縮演算法,通常... ...
定義
在runtime的sync.map包中有定義:
type Map struct {
mu Mutex // 鎖
read atomic.Pointer[readOnly] //包含了readOnly類型的一個struct,下方把 Pointer 也貼了
dirty map[any]*entry // 一個map 存儲數據
misses int // 錯過、沒有命中
}
// readOnly is an immutable struct stored atomically in the Map.read field.
type readOnly struct {
m map[any]*entry // 一個map,這個map是 read持有的
amended bool // true if the dirty map contains some key not in m.
// 追加,這裡已經註釋了 當dirty 的map中的key 不在 m的map中(就是 read的)就顯示為 true
}
// go 的泛型
type Pointer[T any] struct {
_ [0]*T
_ noCopy
v unsafe.Pointer
}
整體的結構就如上圖。
sync.map中有兩個map 都是通過指針的形式 ,指向同一份value,但是key兩個map都有各自存儲。
分析原理
看究竟是如何解決map併發的問題的。
正常讀寫
正常讀寫走 m,就是read那個通過泛型結構體指向的那個 map,通過m這個map進行查找後,讀取或者更改。
這個時候 misses = 0 ,amended=false
追加
如何寫一個key,發現m中沒有,那麼需要去dirty中追加。
開始追加前,需要對dirty進行上鎖,寫完解鎖。
如圖現在追加了一個 d,這個時候 m中沒有這個d的信息。
這個時候 misses = 0 ,amended=true 這個時候有了 dirty的key 不在m中了。
追加後讀寫
這時候就會出現 找d時候,發現m中沒有並
amended=true
,就會去 dirty中找,而且每找一次,都會給misses
加1
這個時候 misses = 1 ,amended=true
dirty 提升
當 misses
等於 len(dirty)
就會觸發dirty提升,替代m。
當再次出現追加的情況,重塑 dirty
這時候把 misses = 0 ,amended=false 複原
刪除
刪除比較麻煩,分為正常刪除,和在上面的各種狀態下進行刪除。
正常刪除
只需要把pointer置為nil就好,value因為沒有對象指向它,在垃圾回收時候,會被標記為白色,被清理。
追加後刪除
正常也是置為nil
刪除後,提升
提升之後,如果重建 dirty,就不會重建這個d
這裡d標記為 expunge 是為了告訴下方,
這個key已經被刪除了,不用同步了,如果出現刪除d的請求,不需要和下方dirty同步了。
而且當再對D進行追加時候,這時候 m中有d,但是,應該要放到dirty中去完成。
總結:
1. map 在擴容時會有併發問題
2.sync.Map 使用了兩個map,分離了擴容問題
3.不會引發擴容的操作(查、改)使用read map
4.可能引發擴容的操作(新增)使用 dirty map
5.不是採用讀寫分離的辦法