为什么sync.Mutex存在?

时间:2019-03-04 12:08:26

标签: go concurrency

为什么我们拥有sync.Mutexsync.RWMutex存在?我可以锁定/解锁rw互斥锁。它们之间的主要区别是什么?

3 个答案:

答案 0 :(得分:3)

的确,只要需要sync.RWMutex,就可以使用sync.Mutex

我认为两者都存在,因为在许多情况下,sync.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(),因为它没有该方法)。

答案 1 :(得分:0)

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

如果我们看一下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所需的时间以及它执行的所有其他操作。

我们看到对对象race的atomic.AddInt32,runtime_SemacquireMutex和其他方法的调用,这会产生开销。

答案 2 :(得分:0)

<块引用>

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

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

<块引用>

考虑遵循#golang RWMutex 算法调整
使编写器与读者和互斥锁一样快

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)