golang中sync.Map解析

sync.Map是一個并發(fā)安全的map,它是通過雙層的數(shù)據(jù)來存儲的,第一層read,可以實現(xiàn)無鎖的讀取,因此sync.Map適合用于讀多寫少的場景,結(jié)構(gòu)如下


1650986247922-ee66b16b-f812-49c7-b232-e9d7fc3719c2.png

個人理解sync.Map的結(jié)構(gòu)有點像常用的緩存設(shè)計,read就是緩存層,它可以進行無鎖的讀??;dirty就是數(shù)據(jù)庫層,它存儲了所有的數(shù)據(jù),需要加鎖進行操作。dirty在一定情況下會提升到read,同時dirty數(shù)據(jù)會從read中進行拷貝

dirty和read的轉(zhuǎn)換

read可以理解為緩存,可以無鎖進行操作,所以很快,dirty即為全量數(shù)據(jù)

  1. dirty提升為read

Map中有一個變量為misses,它記錄了讀取read沒命中的次數(shù),當(dāng)misses次數(shù)超過了dirty中數(shù)據(jù)個數(shù)的時候,就會將dirty提升為read,同時dirty置為nil。每次讀取read失敗的時候都會進行判斷是否需要將dirty提升到read,升級結(jié)果如下圖所示。其實就是將dirty賦值到read.m


1650990276796-2e4117a6-55df-4326-9a74-2055ae997dea.png
  1. 從read復(fù)制數(shù)據(jù)到dirty

在寫入數(shù)據(jù)的時候,如果read未命中,會判斷dirty是否為nil,如果是,則會從read中復(fù)制數(shù)據(jù)到dirty中。注意這里expunged就會產(chǎn)生作用了,在復(fù)制的過程中,如果read中某個entry存儲的value的數(shù)據(jù)為nil,說明這個數(shù)據(jù)被刪除了,次數(shù)dirty不會復(fù)制這個entry,同時會將這個entry.p置為expunged。如下圖所示。至于key4和key6為什么為nil,可以看刪除操作


1650990647868-a82c555a-4b49-4d10-bdc2-9072597512db.png

樣例圖

1650989663922-b0e05bf3-97e0-49c1-9860-35cccc553b95.png

讀取操作

由此可以發(fā)現(xiàn),sync.Map的讀取很簡單,首先無鎖讀取read,如果沒有再去dirty中讀取,其中包括了double check,即加鎖后再check一邊read的數(shù)據(jù)

寫入操作

對于寫入,需要保證read和dirty數(shù)據(jù)一致性,這里有兩種情況,一種是read中有相應(yīng)的key,一種是read中沒有相應(yīng)key
如果read中沒有相應(yīng)的鍵,只需要在dirty中寫入相應(yīng)的key/value就行了,當(dāng)然這里需要加鎖進行寫入即可。例如,如果我們此時需要插入key5,此時read中并沒有key5,則加鎖后往dirty中設(shè)置key5即可,同樣的,key3也是這種情況
如果read中有相應(yīng)的鍵,這里需要對key對應(yīng)的entry中保存的指針進行判斷:

  1. 如果entry.p不為expunged,可以將其直接指向value即可,因為dirty和read.m的結(jié)構(gòu)都是map[interface{}]*entry,它們都是指針結(jié)構(gòu),因此只需要替換掉entry中的指針,就可以實現(xiàn)dirty和read同時更新。對應(yīng)上圖中key1和key4情況
  2. 如果entry.p為expunged,那說明這個key在read中存在,但是在dirty中不存在。這種情況就不能直接更新entry.p了,這樣會導(dǎo)致數(shù)據(jù)不同步。這種情況下,就需要加鎖更新dirty和read了,對應(yīng)上圖中key2的情況

刪除操作

對于刪除操作,也需要保證數(shù)據(jù)一致性,同樣分為read中有相應(yīng)的key和read中沒有相應(yīng)的key兩種情況
如果read中沒有相應(yīng)的key,則直接加鎖后從dirty中刪除key即可
如果read中有相應(yīng)的key,則通過將entry.p置為nil即可

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容