返回顶部
首页 > 资讯 > 后端开发 > GO >Golang并发之RWMutex怎么使用
  • 285
分享到

Golang并发之RWMutex怎么使用

2023-07-05 22:07:14 285人浏览 独家记忆
摘要

这篇文章主要介绍“golang并发之RWMutex怎么使用”,在日常操作中,相信很多人在Golang并发之RWMutex怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Golang并发之RWMutex怎

这篇文章主要介绍“golang并发之RWMutex怎么使用”,在日常操作中,相信很多人在Golang并发之RWMutex怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Golang并发之RWMutex怎么使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

RWMutex

读写互斥是一种同步原语,它允许多个协程同时访问共享资源,同时确保一次只有一个协程可以修改资源。相较于互斥锁,读写互斥锁在读操作比写操作更频繁的情况下,可以带来更好的性能表现。

Go 语言中,RWMutex 是一种读写互斥锁的实现,它提供了一种简单有效的方式来管理对共享资源的并发访问。它提供了两种类型的锁:读锁写锁

读锁(RLock()TryRLock()RUnlock() 方法)

RWMutex 的读锁是一种共享锁,当一个协程获取了读锁后,其他协程也可以同时获取读锁,从而允许并发的读操作。

写锁(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 mainimport (   "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怎么使用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

您可能感兴趣的文档:

--结束END--

本文标题: Golang并发之RWMutex怎么使用

本文链接: https://lsjlt.com/news/355615.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Golang并发之RWMutex怎么使用
    这篇文章主要介绍“Golang并发之RWMutex怎么使用”,在日常操作中,相信很多人在Golang并发之RWMutex怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Golang并发之RWMutex怎...
    99+
    2023-07-05
  • Golang并发之RWMutex的用法详解
    目录前言RWMutexRWMutex 结构体介绍简单读写场景示例基于 RWMutex 实现一个简单的协程安全的缓存RWMutex 易错场景没有正确的加锁和解锁重复加锁读操作内嵌写操作...
    99+
    2023-05-14
    Golang并发RWMutex Golang RWMutex Go RWMutex
  • Golang中的RWMutex怎么使用
    本篇内容主要讲解“Golang中的RWMutex怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Golang中的RWMutex怎么使用”吧!RWMutex 的整体模型正如 RWMutex ...
    99+
    2023-07-05
  • Go并发之RWMutex源码分析
    这篇文章主要介绍“Go并发之RWMutex源码分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Go并发之RWMutex源码分析”文章能帮助大家解决问题。RWMutex是一个支持并行读串行写的读写锁...
    99+
    2023-07-05
  • Go并发之RWMutex的源码解析详解
    目录使用场景源码解析RWMutex结构体Lock()方法Unlock()方法RLock()方法RUnlock()方法RWMutex是一个支持并行读串行写的读写锁。RWMutex具有写...
    99+
    2023-03-15
    Go RWMutex源码 Go RWMutex
  • golang并发模型怎么使用
    Golang的并发模型是通过goroutine和channel来实现的。1. Goroutine: Goroutine是轻量级的线程...
    99+
    2023-08-23
    golang
  • Golang并发利器sync.Once怎么使用
    这篇文章主要介绍了Golang并发利器sync.Once怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Golang并发利器sync.Once怎么使用文章都会有所收获,下面我们一起来看看吧。sync.On...
    99+
    2023-07-06
  • Golang开发之接口怎么使用
    今天小编给大家分享一下Golang开发之接口怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。Golang的接口是什么在...
    99+
    2023-07-05
  • Java高并发之CyclicBarrier怎么使用
    这篇文章主要介绍了Java高并发之CyclicBarrier怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java高并发之CyclicBarrier怎么使用文章都会有所收获,下面我们一起来看看吧。Jav...
    99+
    2023-07-05
  • Go语言并发编程之互斥锁Mutex和读写锁RWMutex
    目录一、互斥锁Mutex1、Mutex介绍2、Mutex使用实例二、读写锁RWMutex1、RWMutex介绍2、RWMutex使用实例在并发编程中,多个Goroutine访问同一块...
    99+
    2024-04-02
  • Java并发之怎么使用线程池
    这篇文章主要介绍“Java并发之怎么使用线程池”,在日常操作中,相信很多人在Java并发之怎么使用线程池问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java并发之怎么使用线程池”的疑惑有所帮助!接下来,请跟...
    99+
    2023-06-16
  • Golang并发编程怎么应用
    这篇文章主要讲解了“Golang并发编程怎么应用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Golang并发编程怎么应用”吧!1、通过通信共享并发编程是一个很大的主题,这里只提供一些特定于...
    99+
    2023-07-06
  • golang并发锁如何使用
    这篇文章主要介绍了golang并发锁如何使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇golang并发锁如何使用文章都会有所收获,下面我们一起来看看吧。如果程序用到的数据是多个groutine之间的交互过程...
    99+
    2023-07-05
  • golang并发锁使用详解
    目录互斥锁 sync.Mutex 读写锁 sync.RWMutex 如果程序用到的数据是多个groutine之间的交互过程中产生的,那么使用上文提到的channe...
    99+
    2023-02-23
    golang并发与锁 Golang 并发死锁 Golang 并发锁
  • Golang并发编程之GMP模型怎么实现
    本文小编为大家详细介绍“Golang并发编程之GMP模型怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“Golang并发编程之GMP模型怎么实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。0. 简介传统...
    99+
    2023-07-05
  • C#并发编程之Task类怎么使用
    这篇文章主要介绍了C#并发编程之Task类怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C#并发编程之Task类怎么使用文章都会有所收获,下面我们一起来看看吧。Task.RunTask是建立在线程池之上...
    99+
    2023-07-05
  • golang怎么并发数据
    Go语言是一种以并发编程为设计重点的语言,它具有轻量级线程(即goroutine)和可扩展的通信机制,使得其在处理并发数据时变得非常高效。本文将介绍如何使用goroutine和通道在Go中实现并发数据处理。goroutine是一种轻量级线程...
    99+
    2023-05-14
  • Java并发编程之LinkedBlockingQueue队列怎么使用
    这篇文章主要介绍了Java并发编程之LinkedBlockingQueue队列怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java并发编程之LinkedBlockingQueue队列怎么使用文章都会有...
    99+
    2023-06-30
  • Golang并发编程之Channel详解
    目录0. 简介1. channel数据结构2. channel创建3. 数据发送3.1 空通道的数据发送3.2 直接发送3.3 缓存区3.4 阻塞发送4. 接收数据4.1 空通道的数...
    99+
    2023-05-19
    Golang并发编程Channel Golang并发编程 Golang Channel
  • golang怎么控制并发数
    在Go中,可以使用goroutine和channel来控制并发数。 首先,可以使用make函数创建一个带有指定并发数的channel...
    99+
    2023-10-21
    golang
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作