




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第一文帶你深入探究Go語(yǔ)言中的sync.Map目錄1.Map的基本實(shí)現(xiàn)原理2.sync.Map的實(shí)現(xiàn)原理2.1sync.Map的結(jié)構(gòu)體定義2.2sync.Map的讀取實(shí)現(xiàn)2.3sync.Map的寫(xiě)入實(shí)現(xiàn)2.4sync.Map的刪除實(shí)現(xiàn)2.5sync.Map的遍歷實(shí)現(xiàn)在Go語(yǔ)言中,有一個(gè)非常實(shí)用的并發(fā)安全的Map實(shí)現(xiàn):sync.Map,它是在Go1.9版本中引入的。相比于標(biāo)準(zhǔn)庫(kù)中的map,它的最大特點(diǎn)就是可以在并發(fā)情況下安全地讀寫(xiě),而不需要加鎖。在這篇博客中,我們將深入探討sync.Map的基本原理,幫助讀者更好地理解并使用這個(gè)并發(fā)安全的Map。
1.Map的基本實(shí)現(xiàn)原理
在介紹sync.Map的基本實(shí)現(xiàn)原理之前,我們需要先了解一下Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)中的map實(shí)現(xiàn)原理。在Go中,map是基于哈希表實(shí)現(xiàn)的。當(dāng)我們向map中添加元素時(shí),它會(huì)根據(jù)key計(jì)算出一個(gè)哈希值,然后將這個(gè)值映射到一個(gè)桶中。如果該桶中已經(jīng)有了元素,它會(huì)遍歷桶中的元素,查找是否已經(jīng)存在相同的key,如果存在就更新對(duì)應(yīng)的值,否則就添加一個(gè)新的鍵值對(duì)。
下面是一個(gè)簡(jiǎn)單的map示例:
m:=make(map[string]int)
m["a"]=1
m["b"]=2
fmt.Println(m["a"])//Output:1
當(dāng)我們運(yùn)行這段代碼時(shí),Go語(yǔ)言會(huì)自動(dòng)幫我們分配一個(gè)哈希表和若干個(gè)桶,然后將鍵值對(duì)添加到對(duì)應(yīng)的桶中。這樣,當(dāng)我們需要訪問(wèn)某個(gè)key對(duì)應(yīng)的值時(shí),Go語(yǔ)言會(huì)根據(jù)哈希值快速定位到對(duì)應(yīng)的桶,然后遍歷桶中的元素,查找是否有相同的key,如果找到了就返回對(duì)應(yīng)的值。
2.sync.Map的實(shí)現(xiàn)原理
sync.Map是Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)中的一個(gè)并發(fā)安全的Map實(shí)現(xiàn),它可以在并發(fā)情況下安全地讀寫(xiě),而不需要加鎖。那么,它是如何實(shí)現(xiàn)這種并發(fā)安全性的呢?下面我們就來(lái)一步步地解析sync.Map的實(shí)現(xiàn)原理。
2.1sync.Map的結(jié)構(gòu)體定義
首先,讓我們來(lái)看一下sync.Map的結(jié)構(gòu)體定義:
typeMapstruct{
musync.Mutex
readatomic.Value//readOnly
dirtymap[interface{}]interface{}
missesint
dirtyLockeduintptr
}
從上面的代碼中可以看出,sync.Map的實(shí)現(xiàn)主要是依賴于一個(gè)互斥鎖(sync.Mutex)和兩個(gè)map(read和dirty)。其中,read和dirty的作用分別是什么呢?我們先來(lái)看一下read的定義:
typereadOnlystruct{
mmap[interface{}]interface{}
amendedbool
}
可以看到,read只有一個(gè)成員m,它是一個(gè)map類型。而amended則表示read中的鍵值對(duì)是否被修改過(guò)。接下來(lái),我們來(lái)看一下dirty的定義:
typedirtystruct{
mmap[interface{}]interface{}
dirtymap[interface{}]bool
missesint
}
和read不同的是,dirty中包含了兩個(gè)map:m和dirty。其中,m存儲(chǔ)了被修改過(guò)的鍵值對(duì),而dirty則存儲(chǔ)了哪些鍵值對(duì)被修改過(guò)。
2.2sync.Map的讀取實(shí)現(xiàn)
在sync.Map中,讀取操作非常簡(jiǎn)單,直接從readOnly中的m中查找即可。如果readOnly中的鍵值對(duì)被修改過(guò),則需要從dirty中查找。讀取操作的實(shí)現(xiàn)代碼如下:
func(m*Map)Load(keyinterface{})(valueinterface{},okbool){
read,_:=m.read.Load().(readOnly)
value,ok=read.m[key]
if!okread.amended{
m.mu.Lock()
read,_=m.read.Load().(readOnly)
value,ok=read.m[key]
if!okread.amended{
value,ok=read.m[key]
m.mu.Unlock()
return
}
在這段代碼中,我們首先從readOnly中的m中查找鍵值對(duì)。如果鍵值對(duì)不存在且readOnly中的鍵值對(duì)被修改過(guò),則需要獲取互斥鎖,并重新從readOnly中查找。如果還是沒(méi)有找到,那么就從dirty中查找。
2.3sync.Map的寫(xiě)入實(shí)現(xiàn)
在sync.Map中,寫(xiě)入操作需要分兩步完成。首先,我們需要判斷readOnly中的鍵值對(duì)是否被修改過(guò),如果沒(méi)有被修改過(guò),則直接將鍵值對(duì)添加到readOnly中的m中即可。否則,我們需要獲取互斥鎖,然后將鍵值對(duì)添加到dirty中的m中,并將對(duì)應(yīng)的鍵添加到dirty中的dirty中。寫(xiě)入操作的實(shí)現(xiàn)代碼如下:
func(m*Map)Store(key,valueinterface{}){
read,_:=m.read.Load().(readOnly)
ifv,ok:=read.m[key];!ok!read.amended{
m.mu.Lock()
read,_=m.read.Load().(readOnly)
ifv,ok:=read.m[key];!ok{
read=readOnly{m:read.m,amended:true}
read.m[key]=value
m.read.Store(read)
m.mu.Unlock()
}else{
m.mu.Lock()
dirty:=m.dirtyLocked!=0
if!dirty{
m.dirtyLocked=1
m.dirty=make(map[interface{}]interface{})
m.dirty[key]=value
if!ok{
m.dirty[key]=value
m.dirty[key]=true
ifdirty{
m.mu.Unlock()
return
m.read.Store(readOnly{m:read.m,amended:true})
m.mu.Unlock()
}
在這段代碼中,我們首先從readOnly中的m中查找鍵值對(duì)。如果鍵值對(duì)不存在且readOnly中的鍵值對(duì)沒(méi)有被修改過(guò),則需要獲取互斥鎖,并重新從readOnly中查找。如果還是沒(méi)有找到,則將鍵值對(duì)添加到readOnly中的m中,并將amended設(shè)置為true。否則,我們需要獲取互斥鎖,并將鍵值對(duì)添加到dirty中的m中,并將對(duì)應(yīng)的鍵添加到dirty中的dirty中。如果dirty中已經(jīng)存在該鍵,則只需要更新dirty中的鍵值即可。如果dirty中沒(méi)有該鍵,則需要在dirty中添加該鍵,并將該鍵的dirty置為true。
接下來(lái),我們需要判斷dirty是否被鎖定。如果dirty被鎖定,則直接退出函數(shù)。否則,我們需要將readOnly中的amended設(shè)置為true,并將readOnly存儲(chǔ)回read中。
2.4sync.Map的刪除實(shí)現(xiàn)
在sync.Map中,刪除操作也需要分兩步完成。首先,我們需要判斷readOnly中的鍵值對(duì)是否被修改過(guò),如果沒(méi)有被修改過(guò),則直接從readOnly中的m中刪除鍵值對(duì)即可。否則,我們需要獲取互斥鎖,然后將鍵添加到dirty中的dirty中,并將dirty中的對(duì)應(yīng)鍵的值設(shè)置為false。刪除操作的實(shí)現(xiàn)代碼如下:
func(m*Map)Delete(keyinterface{}){
read,_:=m.read.Load().(readOnly)
if_,ok:=read.m[key];ok||read.amended{
m.mu.Lock()
read,_=m.read.Load().(readOnly)
if_,ok:=read.m[key];ok||read.amended{
ifm.dirty==nil{
m.dirty=make(map[interface{}]interface{})
m.dirty[key]=false
m.dirty[key]=true
m.read.Store(readOnly{m:read.m,amended:true})
m.mu.Unlock()
}
在這段代碼中,我們首先從readOnly中的m中查找鍵值對(duì)。如果鍵值對(duì)存在或者readOnly中的鍵值對(duì)被修改過(guò),則需要獲取互斥鎖,并重新從readOnly中查找。如果還是沒(méi)有找到,則將鍵添加到dirty中的dirty中,并將dirty中的對(duì)應(yīng)鍵的值設(shè)置為false。接下來(lái),我們需要判斷dirty是否為nil,如果為nil,則需要將dirty初始化為一個(gè)空map。然后,我們將鍵添加到dirty中,并將dirty中的對(duì)應(yīng)鍵的值設(shè)置為true。最后,我們將readOnly中的amended設(shè)置為true,并將readOnly存儲(chǔ)回read中。
2.5sync.Map的遍歷實(shí)現(xiàn)
在sync.Map中,遍歷操作需要將readOnly和dirty中的所有鍵值對(duì)進(jìn)行合并,并返回所有未被刪除的鍵值對(duì)。遍歷操作的實(shí)現(xiàn)代碼如下:
func(m*Map)Range(ffunc(key,valueinterface{})bool){
read,_:=m.read.Load().(readOnly)
ifread.amended{
m.mu.Lock()
read,_=m.read.Load().(readOnly)
ifread.amended{
read=readOnly{
m:merge(read.m,m.dirty),
read.amended=false
m.read.Store(read)
m.dirty=nil
m.mu.Unlock()
fork,v:=rangeread.m{
if!f(k,v){
break
funcmerge(m1,m2map[interface{}]interface{})map[interface{}]interface{}{
iflen(m1)==0len(m2)==0{
returnnil
iflen(m1)==0{
returnm2
iflen(m2)==0{
returnm1
m:=make(map[interface{}]interface{})
fork,v:=rangem1{
m[k]=v
fork,v:=rangem2{
if_,ok:=m[k];!ok||!v.(bool){
m[k]=v
returnm
}
在這段代碼中,我們首先從readOnly中獲取所有的鍵值對(duì),并檢查是否有鍵值對(duì)被修改過(guò)。如果鍵值對(duì)被修改過(guò),則需要獲取互斥鎖,并將readOnly和dirty中的鍵值對(duì)合并,然后將合并后的鍵值對(duì)存儲(chǔ)回readOnly中,并將dirty設(shè)置為nil。接下來(lái),我們遍歷readOnly中的所有鍵值對(duì),并調(diào)用f函數(shù)來(lái)處理鍵值對(duì)。如果f函數(shù)返回false,則遍歷過(guò)程結(jié)束
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 企業(yè)內(nèi)部管理中的區(qū)塊鏈技術(shù)應(yīng)用
- 從數(shù)據(jù)安全到業(yè)務(wù)協(xié)同看區(qū)塊鏈在供應(yīng)中的應(yīng)用價(jià)值
- 從行業(yè)視角看醫(yī)療數(shù)據(jù)安全及患者信息泄露的預(yù)防措施研究報(bào)告
- 醫(yī)療設(shè)備創(chuàng)新中的知識(shí)產(chǎn)權(quán)保護(hù)方法
- 醫(yī)療健康產(chǎn)業(yè)發(fā)展中的資源規(guī)劃與布局
- AI技術(shù)在醫(yī)療教育中的倫理挑戰(zhàn)與對(duì)策
- 公司出資買房合同范例
- 醫(yī)療大數(shù)據(jù)在健康管理中的價(jià)值與隱私保護(hù)的平衡
- 代理招商授權(quán)合同范例
- 亞馬遜運(yùn)營(yíng)托管合同范例
- (四調(diào))武漢市2025屆高中畢業(yè)生四月調(diào)研考試 數(shù)學(xué)試卷(含答案詳解)
- 部編人教版語(yǔ)文小學(xué)六年級(jí)下冊(cè)第四單元主講教材解讀(集體備課)
- GB/T 13477.8-2002建筑密封材料試驗(yàn)方法第8部分:拉伸粘結(jié)性的測(cè)定
- 英文詩(shī)歌朗誦短篇帶翻譯
- 導(dǎo)尿及留置導(dǎo)尿的護(hù)理進(jìn)展
- 工商管理專業(yè)調(diào)查匯總報(bào)告
- 4M變化點(diǎn)管理看板模板
- 多聯(lián)機(jī)電控常見(jiàn)故障及維修(課堂PPT)
- 點(diǎn)焊機(jī)焊接變壓器的結(jié)構(gòu)特點(diǎn)和設(shè)計(jì)制造
- DLT667-1999(IEC60870-5-103)規(guī)約詳解
- 緩蝕阻垢劑安全技術(shù)說(shuō)明書(shū)MSDS
評(píng)論
0/150
提交評(píng)論