真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Go語言之讀寫鎖

前面的有篇文章在講資源競爭的時(shí)候,提到了互斥鎖?;コ怄i的根本就是當(dāng)一個(gè)goroutine訪問的時(shí)候,其他goroutine都不能訪問,這樣肯定保證了資源的同步,避免了競爭,不過也降低了性能。

十余年的貴定網(wǎng)站建設(shè)經(jīng)驗(yàn),針對設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。營銷型網(wǎng)站的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整貴定建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)建站從事“貴定網(wǎng)站設(shè)計(jì)”,“貴定網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。


仔細(xì)剖析我們的場景,當(dāng)我們讀取一個(gè)數(shù)據(jù)的時(shí)候,如果這個(gè)數(shù)據(jù)永遠(yuǎn)不會(huì)被修改,那么其實(shí)是不存在資源競爭的問題的。因?yàn)閿?shù)據(jù)是不變的,不管怎么讀取,多少goroutine同時(shí)讀取,都是可以的。


所以其實(shí)讀取并不是問題,問題主要是修改。修改的數(shù)據(jù)要同步,這樣其他goroutine才可以感知到。所以真正的互斥應(yīng)該是讀取和修改、修改和修改之間,讀取和讀取是沒有互斥操作的。


所以這就延伸出來另外一種鎖,叫做讀寫鎖。


讀寫鎖可以讓多個(gè)讀操作同時(shí)并發(fā),同時(shí)讀取,但是對于寫操作是完全互斥的。也就是說,當(dāng)一個(gè)goroutine進(jìn)行寫操作的時(shí)候,其他goroutine既不能進(jìn)行讀操作,也不能進(jìn)行寫操作。


var countint
var wg sync.WaitGroup
func main(){    wg.Add(10)    for i:=0;i<5;i++{            go read(i)    }        for i:=0;i<5;i++{            go write(i);    }    wg.Wait()}func read(nint){    fmt.Printf("讀goroutine %d 正在讀取...\n",n)    v:= count    fmt.Printf("讀goroutine %d 讀取結(jié)束,值為:%d\n", n,v)    wg.Done()
}
func write(nint){    fmt.Printf("寫goroutine %d 正在寫入...\n",n)    v:= rand.Intn(1000)    count= v    fmt.Printf("寫goroutine %d 寫入結(jié)束,新值為:%d\n", n,v)    wg.Done()
}


以上我們定義了一個(gè)共享的資源count,并且聲明了兩個(gè)函數(shù)read和write進(jìn)行讀寫。在main函數(shù)的測試中,我們同時(shí)啟動(dòng)了 5 個(gè)讀寫goroutine進(jìn)行讀寫操作,通過打印的結(jié)果來看,寫入操作是處于競爭狀態(tài)的,有的寫入操作被覆蓋了。通過go build -race也可以看到更明細(xì)的競爭態(tài)。


針對這種情況,第一個(gè)方案是加互斥鎖,同時(shí)只能有一個(gè)goroutine可以操作count。但是這種方法性能比較慢,而且我們說的讀操作可以不互斥,所以這種情況比較適合使用讀寫鎖。


var countint
var wg sync.WaitGroup
var rw sync.RWMutex
func main(){    wg.Add(10)    for i:=0;i<5;i++{            go read(i)    }        for i:=0;i<5;i++{            go write(i);    }    wg.Wait()}func read(nint){    rw.RLock()    fmt.Printf("讀goroutine %d 正在讀取...\n",n)    v:= count    fmt.Printf("讀goroutine %d 讀取結(jié)束,值為:%d\n", n,v)    wg.Done()    rw.RUnlock()}func write(nint){    rw.Lock()    fmt.Printf("寫goroutine %d 正在寫入...\n",n)    v:= rand.Intn(1000)    count= v    fmt.Printf("寫goroutine %d 寫入結(jié)束,新值為:%d\n", n,v)    wg.Done()    rw.Unlock()
}


我們在read里使用讀鎖,也就是RLock和RUnlock,寫鎖的方法名和我們平時(shí)使用的一樣,是Lock和Unlock。這樣,我們就使用了讀寫鎖,可以并發(fā)地讀,但是同時(shí)只能有一個(gè)寫,并且寫的時(shí)候不能進(jìn)行讀操作?,F(xiàn)在我們再運(yùn)行代碼,可以從輸出的數(shù)據(jù)看到,可以讀到新值了。


我們同時(shí)也可以使用go build -race檢測,也沒有競爭提示了。


我們在做Java開發(fā)的時(shí)候,肯定知道SynchronizedMap這個(gè)Map,它是一個(gè)在多線程下安全的Map,我們可以通過Collections.synchronizedMap(Map)來獲取一個(gè)安全的Map。下面我們看看如何使用讀寫鎖,基于Go語言來實(shí)現(xiàn)一個(gè)安全的Map。


package common
import(    "sync")
//安全的Map
typeSynchronizedMapstruct{    rw*sync.RWMutex    data map[interface{}]interface{}
}
//存儲(chǔ)操作
func(sm*SynchronizedMap)Put(k,vinterface{}){    sm.rw.Lock()    defer sm.rw.Unlock()    sm.data[k]=v
}
//獲取操作
func(sm*SynchronizedMap)Get(kinterface{})interface{}{    sm.rw.RLock()    defer sm.rw.RUnlock()    return sm.data[k]
}
//刪除操作
func(sm*SynchronizedMap)Delete(kinterface{}){    sm.rw.Lock()    defer sm.rw.Unlock()    delete(sm.data,k)
}
//遍歷Map,并且把遍歷的值給回調(diào)函數(shù),可以讓調(diào)用者控制做任何事情
func(sm*SynchronizedMap)Each(cb func(interface{},interface{})){    sm.rw.RLock()    defer sm.rw.RUnlock()    for k, v:= range sm.data{        cb(k,v)    }
}
//生成初始化一個(gè)SynchronizedMap
funcNewSynchronizedMap()*SynchronizedMap{    return&SynchronizedMap{        rw:new(sync.RWMutex),        data:make(map[interface{}]interface{}),    }
}


這個(gè)安全的Map被我們定義為一個(gè)SynchronizedMap的結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體里有兩個(gè)字段,一個(gè)是讀寫鎖rw,一個(gè)是存儲(chǔ)數(shù)據(jù)的data,data是map類型。


然后就是給SynchronizedMap定義一些方法,如果這些方法是增刪改的,就要使用寫鎖;如果是只讀的,就使用讀鎖。這樣就保證了我們數(shù)據(jù)data在多個(gè)goroutine下的安全性。


有了這個(gè)安全的Map我們就可以在多goroutine下增刪改查數(shù)據(jù)了,都是安全的。


這里定義了一個(gè)Each方法,這個(gè)方法很有意思,用過Gradle的都知道,也有類似遍歷Map的方法。這個(gè)方法我們可以傳入一個(gè)回調(diào)函數(shù)作為參數(shù),來對我們遍歷的SynchronizedMap數(shù)據(jù)進(jìn)行處理,比如我打印SynchronizedMap中的數(shù)據(jù)。


sm.Each(func(kinterface{}, vinterface{}){
    fmt.Println(k," is ",v)
}


sm就是一個(gè)SynchronizedMap,非常簡潔吧。


以上就是讀寫鎖使用的一個(gè)例子。我們可以把這個(gè)map數(shù)據(jù)當(dāng)成緩存數(shù)據(jù),或者當(dāng)成數(shù)據(jù)庫,然后使用讀寫鎖進(jìn)行控制,可以多讀,但是只能有一個(gè)寫。


網(wǎng)站名稱:Go語言之讀寫鎖
瀏覽路徑:http://weahome.cn/article/jpocph.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部