最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go并發(fā)之RWMutex的源碼解析詳解

 更新時間:2023年03月15日 09:49:22   作者:Shine4YG  
RWMutex是一個支持并行讀串行寫的讀寫鎖。RWMutex具有寫操作優(yōu)先的特點(diǎn),寫操作發(fā)生時,僅允許正在執(zhí)行的讀操作執(zhí)行,后續(xù)的讀操作都會被阻塞。本文就來從源碼解析一下RWMutex的使用

RWMutex是一個支持并行讀串行寫的讀寫鎖。RWMutex具有寫操作優(yōu)先的特點(diǎn),寫操作發(fā)生時,僅允許正在執(zhí)行的讀操作執(zhí)行,后續(xù)的讀操作都會被阻塞。

使用場景

RWMutex常用于大量并發(fā)讀,少量并發(fā)寫的場景;比如微服務(wù)配置更新、交易路由緩存等場景。相對于Mutex互斥鎖,RWMutex讀寫鎖具有更好的讀性能。

下面以 “多個協(xié)程并行讀取str變量,一個協(xié)程每100毫秒定時更新str變量” 場景為例,進(jìn)行RWMutex讀寫鎖和Mutex互斥鎖的性能對比。

// 基于RWMutex的實(shí)現(xiàn)
var rwLock sync.RWMutex
var str1 = "hello"

func readWithRWLock() string {
    rwLock.RLock()
    defer rwLock.RUnlock()
    return str1
}

func writeWithRWLock() {
    rwLock.Lock()
    str1 = time.Now().Format("20060102150405")
    rwLock.Unlock()
}

// 多個協(xié)程并行讀取string變量,同時每100ms對string變量進(jìn)行1次更新
func BenchmarkRWMutex(b *testing.B) {
    ticker := time.NewTicker(100 * time.Millisecond)
    go func() {
        for range ticker.C {
            writeWithRWLock()
        }
    }()
    b.ResetTimer()
    b.RunParallel(func(pb *testing.PB) {
        for pb.Next() {
            readWithRWLock()
        }
    })
}
// 基于Mutex實(shí)現(xiàn)
var lock sync.Mutex
var str2 = "hello"

func readWithMutex() string {
    lock.Lock()
    defer lock.Unlock()
    return str2
}

func writeWithMutex() {
    lock.Lock()
    str2 = time.Now().Format("20060102150405")
    lock.Unlock()
}

// 多個協(xié)程并行讀取string變量,同時每100ms對string變量進(jìn)行1次更新
func BenchmarkMutex(b *testing.B) {
    ticker := time.NewTicker(100 * time.Millisecond)
    go func() {
        for range ticker.C {
            writeWithMutex()
        }
    }()
    b.ResetTimer()
    b.RunParallel(func(pb *testing.PB) {
        for pb.Next() {
            readWithMutex()
        }
    })
}

RWMutex讀寫鎖和Mutex互斥鎖的性能對比,結(jié)果如下:

# go test 結(jié)果
go test -bench . -benchtime=10s
BenchmarkRWMutex-8      227611413               49.5 ns/op
BenchmarkMutex-8        135363408               87.8 ns/op
PASS
ok      demo    37.800s

源碼解析

RWMutex是一個寫操作優(yōu)先的讀寫鎖,如下圖所示:

  • 寫操作C發(fā)生時,讀操作A和讀操作B正在執(zhí)行,因此寫操作C被掛起;
  • 當(dāng)讀操作D發(fā)生時,由于存在寫操作C等待鎖,所以讀操作D被掛起;
  • 讀操作A和讀操作B執(zhí)行完成,由于沒有讀操作和寫操作正在執(zhí)行,寫操作C被喚醒執(zhí)行;
  • 當(dāng)讀操作E發(fā)生時,由于寫操作C正在執(zhí)行,所以讀操作E被掛起;
  • 當(dāng)寫操作C執(zhí)行完成后,讀操作D和讀操作E被喚醒;

RWMutex結(jié)構(gòu)體

RWMutex由如下變量組成:

  • rwmutexMaxReaders:表示RWMutex能接受的最大讀協(xié)程數(shù)量,超過rwmutexMaxReaders后會發(fā)生panic;
  • wMutex互斥鎖,用于實(shí)現(xiàn)寫操作之間的互斥
  • writerSem:寫操作操作信號量;當(dāng)存在讀操作時,寫操作會被掛起;讀操作全部完成后,通過writerSem信號量喚醒寫操作;
  • readerSem:讀操作信號量;當(dāng)存在寫操作時,讀操作會被掛起;寫操作完成后,通過readerSem信號量喚醒讀操作;
  • readerCount:正在執(zhí)行中的讀操作數(shù)量;當(dāng)不存在寫操作時從0開始計數(shù),為正數(shù);當(dāng)存在寫操作時從負(fù)的rwmutexMaxReaders開始計數(shù),為負(fù)數(shù);
  • readerWait:寫操作等待讀操作的數(shù)量;當(dāng)執(zhí)行Lock()方法時,如果當(dāng)前存在讀操作,會將讀操作的數(shù)量記錄在readerWait中,并掛起寫操作;讀操作執(zhí)行完成后,會更新readerWait,當(dāng)readerWait為0時,喚醒寫操作;
const rwmutexMaxReaders = 1 << 30

type RWMutex struct {
    w           Mutex  // Mutex互斥鎖,用于實(shí)現(xiàn)寫操作之間的互斥

    writerSem   uint32 // 寫操作信號量,用于讀操作喚醒寫操作
    readerSem   uint32 // 讀操作信號量,用于寫操作喚醒讀操作

    readerCount int32  // 讀操作的數(shù)量,不存在寫操作時從0開始計數(shù),存在寫操作時從-rwmutexMaxReaders開始計數(shù)
    readerWait  int32  // 寫操作等待讀操作的數(shù)量
}

Lock()方法

Lock方法用于寫操作獲取鎖,其操作如下:

  • 獲取w互斥鎖,保證同一時刻只有一個寫操作執(zhí)行;
  • readerCount更新為負(fù)數(shù),使后續(xù)發(fā)生的讀操作被阻塞;
  • 如果當(dāng)前存在活躍的讀操作r != 0,寫操作進(jìn)入阻塞狀態(tài)runtime_SemacquireMutex;
func (rw *RWMutex) Lock() {
    // 寫操作之間通過w互斥鎖實(shí)現(xiàn)互斥
    rw.w.Lock()
    // 1.將readerCount更新為負(fù)值,表示當(dāng)前有寫操作;當(dāng)readerCount為負(fù)數(shù)時,新的讀操作會被掛起
    // 2.r表示當(dāng)前正在執(zhí)行的讀操作數(shù)量
    r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
    // r != 0表示當(dāng)前存在正在執(zhí)行的讀操作;寫操作需要等待所有讀操作執(zhí)行完,才能被執(zhí)行;
    if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
        // 將寫操作掛起
        runtime_SemacquireMutex(&rw.writerSem, false, 0)
    }
}

Unlock()方法

Unlock方法用于寫操作釋放鎖,其操作如下:

readerCount更新為正數(shù),表示當(dāng)前不存在活躍的寫操作;

如果更新后的readerCount大于0,表示當(dāng)前寫操作阻塞了readerCount個讀操作,需要將所有被阻塞的讀操作都喚醒;

w互斥鎖釋放,允許其他寫操作執(zhí)行;

func (rw *RWMutex) Unlock() {
    // 將readerCount更新為正數(shù),從0開始計數(shù)
    r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
    if r >= rwmutexMaxReaders {
        throw("sync: Unlock of unlocked RWMutex")
    }
    // 喚醒所有等待寫操作的讀操作 
    for i := 0; i < int(r); i++ {
        runtime_Semrelease(&rw.readerSem, false, 0)
    }
    // 釋放w互斥鎖,允許其他寫操作進(jìn)入
    rw.w.Unlock()
}

RLock()方法

RLock方法用于讀操作獲取鎖,其操作如下:

  • 原子更新readerCount+1;
  • 如果當(dāng)前存在寫操作atomic.AddInt32(&rw.readerCount, 1) < 0,讀操作進(jìn)入阻塞狀態(tài);
func (rw *RWMutex) RLock() {
    // 原子更新readerCount+1
    // 1. readerCount+1為負(fù)數(shù)時,表示當(dāng)前存在寫操作;讀操作需要等待寫操作執(zhí)行完,才能被執(zhí)行
    // 2. readerCount+1不為負(fù)數(shù)時,表示當(dāng)前不存在寫操作,讀操作可以執(zhí)行
    if atomic.AddInt32(&rw.readerCount, 1) < 0 {
        // 將讀操作掛起
        runtime_SemacquireMutex(&rw.readerSem, false, 0)
    }
}

RUnlock()方法

RUnlock方法用于讀操作釋放鎖,其操作如下:

原子更新readerCount-1;

如果當(dāng)前讀操作阻塞了寫操作atomic.AddInt32(&rw.readerCount, -1)<0,原子更新readerWait-1;

當(dāng)readerWait為0時,表示阻塞寫操作的所有讀操作都執(zhí)行完了,喚醒寫操作;

func (rw *RWMutex) RUnlock() {
    // 原子更新readerCount-1
    // 當(dāng)readerCount-1為負(fù)時,表示當(dāng)前讀操作阻塞了寫操作,需要進(jìn)行readerWait的更新
    if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
        rw.rUnlockSlow(r)
    }
}

func (rw *RWMutex) rUnlockSlow(r int32) {
    if r+1 == 0 || r+1 == -rwmutexMaxReaders {
        throw("sync: RUnlock of unlocked RWMutex")
    }
    // 原子操作readerWait-1
    // 當(dāng)readerWait-1為0時,表示導(dǎo)致寫操作阻塞的所有讀操作都執(zhí)行完,將寫操作喚醒
    if atomic.AddInt32(&rw.readerWait, -1) == 0 {
        // 喚醒讀操作
        runtime_Semrelease(&rw.writerSem, false, 1)
    }
}

到此這篇關(guān)于Go并發(fā)之RWMutex的源碼解析詳解的文章就介紹到這了,更多相關(guān)Go RWMutex內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決Golang 中使用WaitGroup的那點(diǎn)坑

    解決Golang 中使用WaitGroup的那點(diǎn)坑

    這篇文章主要介紹了解決Golang 中使用WaitGroup的那點(diǎn)坑,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • 使用Lumberjack+zap進(jìn)行日志切割歸檔操作

    使用Lumberjack+zap進(jìn)行日志切割歸檔操作

    這篇文章主要介紹了使用Lumberjack+zap進(jìn)行日志切割歸檔操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • go基于Gin框架的HTTP接口限速實(shí)踐

    go基于Gin框架的HTTP接口限速實(shí)踐

    HTTP接口在各個業(yè)務(wù)模塊之間扮演著重要的角色,本文主要介紹了go基于Gin框架的HTTP接口限速實(shí)踐,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • Go語言中的并發(fā)模式你了解了嗎

    Go語言中的并發(fā)模式你了解了嗎

    工作中查看項(xiàng)目代碼,發(fā)現(xiàn)會存在使用?GO?語言做并發(fā)的時候出現(xiàn)各種各樣的異常情況,實(shí)際上,出現(xiàn)上述的情況,還是因?yàn)槲覀儗τ?GO?語言的并發(fā)模型和涉及的?GO?語言基礎(chǔ)不夠扎實(shí),所以本文小編就來帶大家深入了解下Go語言中的并發(fā)模式吧
    2023-08-08
  • 完美解決go Fscanf 在讀取文件時出現(xiàn)的問題

    完美解決go Fscanf 在讀取文件時出現(xiàn)的問題

    這篇文章主要介紹了完美解決go Fscanf 在讀取文件時出現(xiàn)的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • go語言VScode?see?'go?help?modules'?(exit?status?1)問題的解決過程

    go語言VScode?see?'go?help?modules'?(exit?statu

    最近上手學(xué)習(xí)go語言,準(zhǔn)備在VSCode上寫程序的時候卻發(fā)現(xiàn)出了一點(diǎn)問題,下面這篇文章主要給大家介紹了關(guān)于go語言VScode?see?'go?help?modules'(exit?status?1)問題的解決過程,需要的朋友可以參考下
    2022-07-07
  • golang實(shí)現(xiàn)LRU緩存淘汰算法的示例代碼

    golang實(shí)現(xiàn)LRU緩存淘汰算法的示例代碼

    這篇文章主要介紹了golang實(shí)現(xiàn)LRU緩存淘汰算法的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • Go 并發(fā)控制context實(shí)現(xiàn)原理剖析(小結(jié))

    Go 并發(fā)控制context實(shí)現(xiàn)原理剖析(小結(jié))

    Golang context是Golang應(yīng)用開發(fā)常用的并發(fā)控制技術(shù),這篇文章主要介紹了Go 并發(fā)控制context實(shí)現(xiàn)原理剖析(小結(jié)),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • GO語言的數(shù)組array與切片slice詳解

    GO語言的數(shù)組array與切片slice詳解

    這篇文章主要介紹了GO語言的數(shù)組array與切片slice,包括了GO語言數(shù)組定義賦值,GO語言多維數(shù)組,GO語言切片等知識點(diǎn)需要的朋友可以參考下
    2022-12-12
  • golang mysql的連接池的具體使用

    golang mysql的連接池的具體使用

    本文主要介紹了golang mysql的連接池的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02

最新評論

古丈县| 西贡区| 乌苏市| 克什克腾旗| 五华县| 高青县| 合肥市| 万盛区| 霞浦县| 禹城市| 依安县| 三江| 康平县| 富宁县| 铜山县| 揭东县| 周口市| 肥城市| 金华市| 嘉荫县| 隆昌县| 上蔡县| 长武县| 介休市| 淮南市| 扬中市| 常德市| 仁寿县| 阿拉善左旗| 尖扎县| 彭州市| 九江县| 平昌县| 浦江县| 康平县| 华安县| 甘泉县| 原阳县| 福泉市| 北辰区| 比如县|