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

Golang并發(fā)之RWMutex的用法詳解

 更新時間:2023年04月06日 09:27:56   作者:陳明勇  
在?Go?語言中,RWMutex?是一種讀寫互斥鎖的實現(xiàn),它提供了一種簡單有效的方式來管理對共享資源的并發(fā)訪問。本文就來和大家詳細聊聊RWMutex的用法吧

前言

在這篇文章 Go Mutex:保護并發(fā)訪問共享資源的利器 中,主要介紹了 Go 語言中互斥鎖 Mutex 的概念、對應(yīng)的字段與方法、基本使用和易錯場景,最后基于 Mutex 實現(xiàn)一個簡單的協(xié)程安全的緩存。而本文,我們來看看另一個更高效的 Go 并發(fā)原語,RWMutex。

準(zhǔn)備好了嗎?喝一杯你最喜歡的飲料,隨著文章一起進入 RWMutex 令人興奮的世界!

說明:本文使用的代碼基于的 Go 版本:1.20.1

RWMutex

讀寫互斥鎖是一種同步原語,它允許多個協(xié)程同時訪問共享資源,同時確保一次只有一個協(xié)程可以修改資源。相較于互斥鎖,讀寫互斥鎖在讀操作比寫操作更頻繁的情況下,可以帶來更好的性能表現(xiàn)。

Go 語言中,RWMutex 是一種讀寫互斥鎖的實現(xiàn),它提供了一種簡單有效的方式來管理對共享資源的并發(fā)訪問。它提供了兩種類型的鎖:讀鎖寫鎖

1、讀鎖(RLock() 、TryRLock()RUnlock() 方法)

RWMutex 的讀鎖是一種共享鎖,當(dāng)一個協(xié)程獲取了讀鎖后,其他協(xié)程也可以同時獲取讀鎖,從而允許并發(fā)的讀操作。

2、寫鎖(Lock()TryLock()Unlock() 方法)

RWMutex 的寫鎖是一種獨占鎖,當(dāng)一個協(xié)程獲取了寫鎖后,其他協(xié)程無法獲取讀鎖或?qū)戞i,直到該協(xié)程釋放寫鎖。在寫鎖未被釋放之前,任何想要獲取讀鎖或?qū)戞i的 goroutine 都會被阻塞。

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

type RWMutex struct {
   w           Mutex        
   writerSem   uint32       // 寫操作等待者
   readerSem   uint32       // 讀操作等待者 
   readerCount atomic.Int32 // 持有讀鎖的 goroutine 數(shù)量
   readerWait  atomic.Int32 // 請求寫鎖時,需要等待完成的讀鎖數(shù)量
}

RWMutex 由以下字段組成:

  • w: 為互斥鎖,用于實現(xiàn)寫操作之間的互斥。
  • writerSem:寫操作的信號量。當(dāng)有 goroutine 請求寫操作時,如果有其他的 goroutine 正在執(zhí)行讀操作,則請求寫操作的 goroutine 將會被阻塞,直到所有的讀操作完成后,通過 writerSem 信號量解除阻塞。
  • readerSem:讀操作的信號量。當(dāng)有 goroutine 請求讀操作時,如果此時存在寫操作,則請求讀操作的 goroutine 將會被阻塞,直到寫操作執(zhí)行完成后,通過 readerSem 信號量解除阻塞并繼續(xù)執(zhí)行。
  • readerCount:讀操作的goroutine數(shù)量,當(dāng)readerCount為正數(shù)時,表示有一個或多個讀操作正在執(zhí)行,如果 readerCount 的值為負數(shù),說明有寫操作正在等待。
  • readerWait:寫操作的 goroutine 等待讀操作完成的數(shù)量。當(dāng)一個寫操作請求執(zhí)行時,如果此時有一個或多個讀操作正在執(zhí)行,則會將讀操作的數(shù)量記錄到readerWait中,并阻塞寫操作所在的goroutine。寫操作所在的goroutine會一直阻塞,直到正在執(zhí)行的所有讀操作完成,此時readerWait的值將被更新為 0,并且寫操作所在的goroutine將被喚醒。

RWMutex 常用方法:

  • Lock():獲取寫鎖,擁有寫操作的權(quán)限;如果讀操作正在執(zhí)行,此方法將會阻塞,直到所有的讀操作執(zhí)行結(jié)束。
  • Unlock():釋放寫鎖,并喚醒其他請求讀鎖的 goroutine。
  • TryLock():嘗試獲取寫鎖,如果獲取成功,返回 true,否則返回 false,不存在阻塞的情況。
  • RLock():獲取讀鎖,讀鎖是共享鎖,可以被多個 goroutine 獲取,但是如果有寫操作正在執(zhí)行或等待執(zhí)行時,此方法將會阻塞,直到寫操作執(zhí)行結(jié)束。
  • RUnlock():釋放讀鎖,如果所有讀操作都結(jié)束并且有等待執(zhí)行的寫操作,則會喚醒對應(yīng)的 goroutine。
  • TryRlock():嘗試獲取讀鎖,如果獲取成功,返回 true,否則返回 false,不存在阻塞的情況。

簡單讀寫場景示例

package main

import (
   "fmt"
   "sync"
   "time"
)

type Counter struct {
   value   int
   rwMutex sync.RWMutex
}

func (c *Counter) GetValue() int {
   c.rwMutex.RLock()
   defer c.rwMutex.RUnlock()
   return c.value
}

func (c *Counter) Increment() {
   c.rwMutex.Lock()
   defer c.rwMutex.Unlock()
   c.value++
}
func main() {
   counter := Counter{value: 0}

   // 讀操作
   for i := 0; i < 10; i++ {
      go func() {
         for {
            fmt.Println("Value: ", counter.GetValue())
            time.Sleep(time.Millisecond)
         }
      }()
   }

   // 寫操作
   for {
      counter.Increment()
      time.Sleep(time.Second)
   }
}

上述代碼示例中定義了一個 Counter 結(jié)構(gòu)體,包含一個 value 字段和一個 sync.RWMutex 實例 rwMutex。該結(jié)構(gòu)體還實現(xiàn)了兩個方法:GetValue()Increment(),分別用于讀取 value 字段的值和對 value 字段的值加一。這兩個方法在訪問 value 字段時,使用了讀寫鎖來保證并發(fā)安全。

main() 函數(shù)中,首先創(chuàng)建了一個 Counter 實例 counter,然后啟動了 10 個協(xié)程,每個協(xié)程會不斷讀取 counter 并打印到控制臺上。同時,main() 函數(shù)也會不斷對 countervalue 值加 1,每次加 1 的操作都會休眠 1 秒鐘。由于使用了讀寫鎖,多個讀操作可以同時進行,而寫操作則會互斥進行,保證了并發(fā)安全。

基于 RWMutex 實現(xiàn)一個簡單的協(xié)程安全的緩存

Go Mutex:保護并發(fā)訪問共享資源的利器 文章中,使用了 Mutex 實現(xiàn)了一個簡單的線程安全的緩存,但并不是最優(yōu)的設(shè)計,對于緩存場景,讀操作比寫操作更頻繁,因此使用 RWMutex 代替 Mutex 會更好。

import "sync"

type Cache struct {
   data    map[string]any
   rwMutex sync.RWMutex
}

func NewCache() *Cache {
   return &Cache{
      data: make(map[string]any),
   }
}

func (c *Cache) Get(key string) (any, bool) {
   c.rwMutex.RLock()
   defer c.rwMutex.RUnlock()
   value, ok := c.data[key]
   return value, ok
}

func (c *Cache) Set(key string, value any) {
   c.rwMutex.Lock()
   defer c.rwMutex.Unlock()
   c.data[key] = value
}

上述代碼實現(xiàn)了一個協(xié)程安全的緩存,通過使用 RWMutex 的讀寫鎖,保證了 Get() 方法可以被多個 goroutine 并發(fā)地執(zhí)行,而且只有在讀操作和寫操作同時存在時才會進行互斥鎖定,有效地提高了并發(fā)性能。

RWMutex 易錯場景

沒有正確的加鎖和解鎖

為了正確使用讀寫鎖,必須正確使用鎖的方法。對于讀操作,必須成對使用 RLock()RUnlock() 方法,否則可能會導(dǎo)致程序 panic 或阻塞。

例如:如果缺少 RLock(),直接使用 RUnlock()方法,程序?qū)?panic,如果缺少 RUnlock() 方法,將會發(fā)生阻塞的形象。

同樣,對于寫操作,必須成對使用 Lock()Unlock() 方法。

最佳實踐是使用 defer 來釋放鎖:為了保證鎖總是被釋放,即使在運行時錯誤或提前返回的情況下,也可以在獲得鎖后立即使用 defer 關(guān)鍵字來調(diào)度相應(yīng)的解鎖方法。

rwMutex.RLock()
defer rwMutex.RUnlock()
// 讀操作

rwMutex.Lock()
defer rwMutex.Unlock()
// 寫操作

重復(fù)加鎖

重復(fù)加鎖操作被稱為可重入操作。不同于其他一些編程語言的鎖實現(xiàn)(例如 Java 的 ReentrantLock),Go 的 mutex 并不支持可重入操作。

由于 RWMutex 內(nèi)部是基于 Mutex 實現(xiàn)的寫操作互斥,如果發(fā)生了重復(fù)加鎖操作,就會導(dǎo)致死鎖。這個易錯場景在上篇文章中也提到了,還給出了代碼示例,感興趣的小伙伴可以去看看。

讀操作內(nèi)嵌寫操作

當(dāng)有協(xié)程執(zhí)行讀操作時,請求執(zhí)行寫操作的協(xié)程會被阻塞。如果在讀操作中嵌入寫操作的代碼,寫操作將調(diào)用 Lock() 方法,從而導(dǎo)致讀操作和寫操作之間形成相互依賴關(guān)系。在這種情況下,讀操作會等待寫操作完成后才能執(zhí)行 RUnlock(),而寫操作則會等待讀操作完成后才能被喚醒繼續(xù)執(zhí)行,從而導(dǎo)致死鎖的狀態(tài)。

小結(jié)

RWMutexGo 中的一種讀寫鎖實現(xiàn),它通過讀鎖允許多個 goroutine 同時執(zhí)行讀操作,當(dāng)有寫操作請求時,必須等待所有讀操作執(zhí)行結(jié)束后才能執(zhí)行寫操作。

RWMutex 的設(shè)計采用了 Write-preferring 方案,即如果有寫操作在等待執(zhí)行,新來的讀操作將會被阻塞,以避免寫操作的饑餓問題。

根據(jù) RWMutex 的特性,它適用于 讀多寫少的高并發(fā)場景,可以實現(xiàn)并發(fā)安全的讀操作,從而減少在鎖競爭中的等待時間。

雖然它能夠給程序帶來了性能的提升,然而,如果使用不當(dāng),就可能會導(dǎo)致 panic 或死鎖等問題。因此,在使用 RWMutex 時需要特別小心,并避免錯誤的用法。

以上就是Golang并發(fā)之RWMutex的用法詳解的詳細內(nèi)容,更多關(guān)于Golang RWMutex的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 舉例詳解Go語言中os庫的常用函數(shù)用法

    舉例詳解Go語言中os庫的常用函數(shù)用法

    這篇文章主要介紹了Go語言中os庫的常用函數(shù)用法,os函數(shù)的使用是Go語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-10-10
  • go程序員日常開發(fā)效率神器匯總

    go程序員日常開發(fā)效率神器匯總

    這篇文章主要介紹了go程序員開發(fā)效率神器包含了go常用開發(fā)工具,go調(diào)試工具,go常用網(wǎng)站,golang常用庫,需要的朋友可以參考下
    2022-11-11
  • 詳解Golang 中的并發(fā)限制與超時控制

    詳解Golang 中的并發(fā)限制與超時控制

    這篇文章主要介紹了詳解Golang 中的并發(fā)限制與超時控制,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • golang切片擴容規(guī)則實現(xiàn)

    golang切片擴容規(guī)則實現(xiàn)

    這篇文章主要介紹了golang切片擴容規(guī)則實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Golang中map的深入探究

    Golang中map的深入探究

    Go中Map是一個KV對集合,下面這篇文章主要給大家介紹了關(guān)于Golang中map探究的相關(guān)資料,文中通過實例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2022-09-09
  • Golang中指針的使用詳解

    Golang中指針的使用詳解

    Golang是一門支持指針的編程語言,指針是一種特殊的變量,存儲了其他變量的地址。通過指針,可以在程序中直接訪問和修改變量的值,避免了不必要的內(nèi)存拷貝和傳遞。Golang中的指針具有高效、安全的特點,在并發(fā)編程和底層系統(tǒng)開發(fā)中得到廣泛應(yīng)用
    2023-04-04
  • GO語言判斷一個網(wǎng)段是否屬于另一個網(wǎng)段的子網(wǎng)

    GO語言判斷一個網(wǎng)段是否屬于另一個網(wǎng)段的子網(wǎng)

    這篇文章主要介紹了GO語言判斷一個網(wǎng)段是否屬于另一個網(wǎng)段的子網(wǎng)的相關(guān)資料,內(nèi)容介紹詳細,具有一定的參考價值,需要的朋友可任意參考一下
    2022-03-03
  • Minio基本介紹及如何搭建Minio集群

    Minio基本介紹及如何搭建Minio集群

    MinIO主要采用Golang語言實現(xiàn),客戶端與存儲服務(wù)器之間采用http/https通信協(xié)議,本文重點給大家介紹什么是Minio?如何搭建Minio集群?感興趣的朋友一起看看吧
    2022-06-06
  • 解決Golang中g(shù)oroutine執(zhí)行速度的問題

    解決Golang中g(shù)oroutine執(zhí)行速度的問題

    這篇文章主要介紹了解決Golang中g(shù)oroutine執(zhí)行速度的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • Go語言中的定時器原理與實戰(zhàn)應(yīng)用

    Go語言中的定時器原理與實戰(zhàn)應(yīng)用

    在Go語言中,Timer和Ticker是處理定時任務(wù)的重要工具,Timer用于一次性事件,而Ticker則用于周期性事件,本文詳細介紹了這兩種定時器的創(chuàng)建、使用和停止方法,并通過實際案例展示了它們在監(jiān)控日志、檢查系統(tǒng)狀態(tài)等方面的應(yīng)用
    2024-10-10

最新評論

新绛县| 大石桥市| 河北区| 内江市| 玛多县| 英超| 太仆寺旗| 宜州市| 龙川县| 来安县| 大连市| 托克托县| 文水县| 镇沅| 大姚县| 武定县| 河源市| 西平县| 洮南市| 开封市| 二连浩特市| 东乡县| 聊城市| 平泉县| 垫江县| 汝州市| 惠安县| 丰台区| 武威市| 罗平县| 贵州省| 乌拉特中旗| 麟游县| 兖州市| 丽江市| 阜阳市| 茶陵县| 竹北市| 集贤县| 襄城县| 孟村|