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()因为它没有该方法)。
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,这会有开销。
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)
- 3 回答
- 0 关注
- 136 浏览
添加回答
举报