为了账号安全,请及时绑定邮箱和手机立即绑定

为什么存在 sync.Mutex?

为什么存在 sync.Mutex?

Go
波斯汪 2023-06-19 11:07:22
为什么sync.Mutex存在而我们有sync.RWMutex?我可以锁定/解锁 rw 互斥体。它们之间的主要区别是什么?
查看完整描述

3 回答

?
喵喔喔

TA贡献1735条经验 获得超5个赞

的确,您可以sync.RWMutex在需要时使用sync.Mutex.

我认为两者都存在,因为在很多情况下 async.Mutex就足够了(您不需要读写级别锁定),并且实现sync.Mutex更简单:需要更少的内存并且很可能更快。


sync.Mutex只有 8 个字节:


type Mutex struct {

    state int32

    sema  uint32

}

虽然sync.RWMutex是 8 + 16 = 24 字节(它包括一个sync.Mutex):


type RWMutex struct {

    w           Mutex  // held if there are pending writers

    writerSem   uint32 // semaphore for writers to wait for completing readers

    readerSem   uint32 // semaphore for readers to wait for completing writers

    readerCount int32  // number of pending readers

    readerWait  int32  // number of departing readers

}

是的,您可以说 8 或 24 个字节无关紧要。只要您只有几个互斥锁,它就不会。


但是将互斥锁放入它应该保护的结构中(嵌入或常规的命名字段)并不少见。现在,如果你有这些结构值的一部分,甚至可能有数千个,那么是的,它会产生明显的不同。


此外,如果您只需要一个互斥量,sync.Mutex则可以减少滥用它的机会(您不会意外调用,RLock()因为它没有该方法)。


查看完整回答
反对 回复 2023-06-19
?
慕妹3146593

TA贡献1820条经验 获得超9个赞

提到的占用更多空间的一部分,它在执行时间方面的效率也较低。


如果我们查看 RWMutex.Lock 的源代码:


// Lock locks rw for writing.

// If the lock is already locked for reading or writing,

// Lock blocks until the lock is available.

func (rw *RWMutex) Lock() {

    if race.Enabled {

        _ = rw.w.state

        race.Disable()

    }

    // First, resolve competition with other writers.

    rw.w.Lock()

    // Announce to readers there is a pending writer.

    r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders

    // Wait for active readers.

    if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {

        runtime_SemacquireMutex(&rw.writerSem, false)

    }

    if race.Enabled {

        race.Enable()

        race.Acquire(unsafe.Pointer(&rw.readerSem))

        race.Acquire(unsafe.Pointer(&rw.writerSem))

    }

}

我们可以看到它调用了 Mutex.Lock,因此它花费了与 Mutex.Lock 相同的时间加上它所做的所有其他事情。


我们看到调用了atomic.AddInt32、runtime_SemacquireMutex等对象的方法race,这会有开销。


查看完整回答
反对 回复 2023-06-19
?
牛魔王的故事

TA贡献1830条经验 获得超3个赞

sync.Mutex 的实现更简单:需要更少的内存并且很可能更快。

检查CL 329769(目前由Dmitry Vyukov进行的实验)是否会进入 Go 1.18 将会很有趣:

考虑以下#golang RWMutex 算法调整
使编写者与读者和 Mutex 一样快

name                old time/op  new time/op  delta

RWMutexWrite        22.3ns ± 0%  13.4ns ± 0%  -40.23%  (p=0.000 n=9+9)

RWMutexRead         13.4ns ± 0%  13.0ns ± 1%   -2.40%  (p=0.000 n=10+10)

RWMutexUncontended  42.1ns ± 0%  36.8ns ± 0%  -12.69%  (p=0.003 n=5+7)


查看完整回答
反对 回复 2023-06-19
  • 3 回答
  • 0 关注
  • 97 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信