面试题答案
一键面试原因分析
sync.RWMutex
设计初衷是为了在读多写少场景下提升性能。读锁可以被多个读操作同时持有,而写锁则是独占的。当有大量读操作不断获取读锁时,写操作由于需要独占锁,就可能会长时间无法获取到锁,从而导致写操作饥饿。
解决方案及代码示例
- 公平锁机制
- 思路:通过维护一个等待队列,按照请求顺序分配锁,使得写操作能按照顺序获取锁,避免饥饿。
- 代码示例
package main
import (
"fmt"
"sync"
"time"
)
type FairMutex struct {
sync.Mutex
readers int
writers int
writerCh chan struct{}
}
func NewFairMutex() *FairMutex {
return &FairMutex{
writerCh: make(chan struct{}, 1),
}
}
func (fm *FairMutex) RLock() {
fm.Lock()
for fm.writers > 0 {
fm.Unlock()
time.Sleep(time.Millisecond)
fm.Lock()
}
fm.readers++
fm.Unlock()
}
func (fm *FairMutex) RUnlock() {
fm.Lock()
fm.readers--
if fm.readers == 0 && len(fm.writerCh) > 0 {
close(fm.writerCh)
}
fm.Unlock()
}
func (fm *FairMutex) Lock() {
fm.Lock()
fm.writers++
for fm.readers > 0 || len(fm.writerCh) > 0 {
fm.Unlock()
fm.writerCh <- struct{}{}
fm.Lock()
}
}
func (fm *FairMutex) Unlock() {
fm.writers--
if fm.writers == 0 && len(fm.writerCh) > 0 {
close(fm.writerCh)
}
fm.Unlock()
}
- 限制读操作数量
- 思路:设定一个最大读操作数量,当读操作达到这个数量后,不再允许新的读操作获取读锁,从而给写操作机会。
- 代码示例
package main
import (
"fmt"
"sync"
"time"
)
type LimitingMutex struct {
sync.RWMutex
maxReaders int
currentReaders int
}
func NewLimitingMutex(max int) *LimitingMutex {
return &LimitingMutex{
maxReaders: max,
}
}
func (lm *LimitingMutex) RLock() {
for {
lm.RLock()
if lm.currentReaders < lm.maxReaders {
lm.currentReaders++
lm.RUnlock()
break
}
lm.RUnlock()
time.Sleep(time.Millisecond)
}
}
func (lm *LimitingMutex) RUnlock() {
lm.RLock()
lm.currentReaders--
lm.RUnlock()
}