面试题答案
一键面试sync.Mutex适用场景
- 读写频繁且写操作较多的场景:当读写操作频繁发生,并且写操作相对较多时,使用
sync.Mutex
。因为sync.Mutex
是互斥锁,同一时间只允许一个goroutine进行读写操作,能有效保证数据一致性,避免写操作导致的数据冲突。 - 对数据一致性要求极高的场景:任何读写操作都不允许并发执行,以确保数据在任何时刻都是一致的。
sync.RWMutex适用场景
- 读操作远多于写操作的场景:
sync.RWMutex
是读写锁,允许多个goroutine同时进行读操作,只有写操作时才会独占锁。在这种场景下,读操作可以并发执行,提高了程序的并发性能。 - 对读性能要求较高的场景:由于读操作可以并发,在需要快速读取数据的场景下,使用
RWMutex
能提升程序的响应速度。
区别
- 并发读写能力:
sync.Mutex
:同一时间只允许一个goroutine进行读写操作,无论是读还是写,都需要获取锁,读写不能并发。sync.RWMutex
:读操作可以并发执行,多个读操作可以同时进行;而写操作时,会独占锁,不允许其他读写操作同时进行。
- 性能:
- 在写操作较多的场景下,
sync.Mutex
性能较好,因为它不需要处理读操作并发的复杂逻辑。 - 在读操作远多于写操作的场景下,
sync.RWMutex
性能更优,读操作并发执行提高了效率。
- 在写操作较多的场景下,
代码示例
使用sync.Mutex
package main
import (
"fmt"
"sync"
)
var (
data int
mutex sync.Mutex
)
func write(wg *sync.WaitGroup) {
defer wg.Done()
mutex.Lock()
data++
mutex.Unlock()
}
func read(wg *sync.WaitGroup) {
defer wg.Done()
mutex.Lock()
fmt.Println("Read data:", data)
mutex.Unlock()
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go write(&wg)
}
for i := 0; i < 5; i++ {
wg.Add(1)
go read(&wg)
}
wg.Wait()
}
使用sync.RWMutex
package main
import (
"fmt"
"sync"
)
var (
data int
rwmutex sync.RWMutex
)
func write(wg *sync.WaitGroup) {
defer wg.Done()
rwmutex.Lock()
data++
rwmutex.Unlock()
}
func read(wg *sync.WaitGroup) {
defer wg.Done()
rwmutex.RLock()
fmt.Println("Read data:", data)
rwmutex.RUnlock()
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go write(&wg)
}
for i := 0; i < 5; i++ {
wg.Add(1)
go read(&wg)
}
wg.Wait()
}
在上述代码中,sync.Mutex
示例中读写操作都需要获取互斥锁,而sync.RWMutex
示例中读操作使用RLock
获取读锁,允许多个读操作并发,写操作使用Lock
获取写锁,独占资源。