中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Golang并發之RWMutex怎么使用

發布時間:2023-05-09 14:25:33 來源:億速云 閱讀:99 作者:zzz 欄目:開發技術

這篇文章主要介紹“Golang并發之RWMutex怎么使用”,在日常操作中,相信很多人在Golang并發之RWMutex怎么使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Golang并發之RWMutex怎么使用”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

RWMutex

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

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

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

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

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

RWMutex 的寫鎖是一種獨占鎖,當一個協程獲取了寫鎖后,其他協程無法獲取讀鎖或寫鎖,直到該協程釋放寫鎖。在寫鎖未被釋放之前,任何想要獲取讀鎖或寫鎖的 goroutine 都會被阻塞。

Golang并發之RWMutex怎么使用

RWMutex 結構體介紹

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

RWMutex 由以下字段組成:

  • w: 為互斥鎖,用于實現寫操作之間的互斥。

  • writerSem:寫操作的信號量。當有 goroutine 請求寫操作時,如果有其他的 goroutine 正在執行讀操作,則請求寫操作的 goroutine 將會被阻塞,直到所有的讀操作完成后,通過 writerSem 信號量解除阻塞。

  • readerSem:讀操作的信號量。當有 goroutine 請求讀操作時,如果此時存在寫操作,則請求讀操作的 goroutine 將會被阻塞,直到寫操作執行完成后,通過 readerSem 信號量解除阻塞并繼續執行。

  • readerCount:讀操作的goroutine數量,當readerCount為正數時,表示有一個或多個讀操作正在執行,如果 readerCount 的值為負數,說明有寫操作正在等待。

  • readerWait:寫操作的 goroutine 等待讀操作完成的數量。當一個寫操作請求執行時,如果此時有一個或多個讀操作正在執行,則會將讀操作的數量記錄到readerWait中,并阻塞寫操作所在的goroutine。寫操作所在的goroutine會一直阻塞,直到正在執行的所有讀操作完成,此時readerWait的值將被更新為 0,并且寫操作所在的goroutine將被喚醒。

RWMutex 常用方法:

  • Lock():獲取寫鎖,擁有寫操作的權限;如果讀操作正在執行,此方法將會阻塞,直到所有的讀操作執行結束。

  • Unlock():釋放寫鎖,并喚醒其他請求讀鎖的 goroutine

  • TryLock():嘗試獲取寫鎖,如果獲取成功,返回 true,否則返回 false,不存在阻塞的情況。

  • RLock():獲取讀鎖,讀鎖是共享鎖,可以被多個 goroutine 獲取,但是如果有寫操作正在執行或等待執行時,此方法將會阻塞,直到寫操作執行結束。

  • RUnlock():釋放讀鎖,如果所有讀操作都結束并且有等待執行的寫操作,則會喚醒對應的 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 結構體,包含一個 value 字段和一個 sync.RWMutex 實例 rwMutex。該結構體還實現了兩個方法:GetValue()Increment(),分別用于讀取 value 字段的值和對 value 字段的值加一。這兩個方法在訪問 value 字段時,使用了讀寫鎖來保證并發安全。

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

基于 RWMutex 實現一個簡單的協程安全的緩存

在 Go Mutex:保護并發訪問共享資源的利器 文章中,使用了 Mutex 實現了一個簡單的線程安全的緩存,但并不是最優的設計,對于緩存場景,讀操作比寫操作更頻繁,因此使用 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
}

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

RWMutex 易錯場景

沒有正確的加鎖和解鎖

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

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

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

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

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

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

重復加鎖

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

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

讀操作內嵌寫操作

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

到此,關于“Golang并發之RWMutex怎么使用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

牙克石市| 墨竹工卡县| 惠州市| 阿巴嘎旗| 边坝县| 贡觉县| 梁山县| 方山县| 六盘水市| 无锡市| 都兰县| 固镇县| 华亭县| 磐石市| 织金县| 疏勒县| 德化县| 上蔡县| 铜川市| 南华县| 高台县| 子洲县| 共和县| 扶风县| 色达县| 林芝县| 渭南市| 乐业县| 峡江县| 安溪县| 辽阳县| 孟连| 嵩明县| 九江市| 和顺县| 延川县| 连平县| 新余市| 自贡市| 彭泽县| 大埔县|