MST

星途 面试题库

面试题:Go中sync.Mutex与sync.RWMutex的应用场景及区别

请详细阐述在Go语言并发编程中,sync.Mutex和sync.RWMutex分别适用于哪些场景,它们之间有什么区别。并编写代码示例说明在一个需要读写操作的场景下,如何正确使用这两种锁来保证数据的一致性和并发安全性。
23.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

sync.Mutex适用场景

  1. 读写频繁且写操作较多的场景:当读写操作频繁发生,并且写操作相对较多时,使用sync.Mutex。因为sync.Mutex是互斥锁,同一时间只允许一个goroutine进行读写操作,能有效保证数据一致性,避免写操作导致的数据冲突。
  2. 对数据一致性要求极高的场景:任何读写操作都不允许并发执行,以确保数据在任何时刻都是一致的。

sync.RWMutex适用场景

  1. 读操作远多于写操作的场景sync.RWMutex是读写锁,允许多个goroutine同时进行读操作,只有写操作时才会独占锁。在这种场景下,读操作可以并发执行,提高了程序的并发性能。
  2. 对读性能要求较高的场景:由于读操作可以并发,在需要快速读取数据的场景下,使用RWMutex能提升程序的响应速度。

区别

  1. 并发读写能力
    • sync.Mutex:同一时间只允许一个goroutine进行读写操作,无论是读还是写,都需要获取锁,读写不能并发。
    • sync.RWMutex:读操作可以并发执行,多个读操作可以同时进行;而写操作时,会独占锁,不允许其他读写操作同时进行。
  2. 性能
    • 在写操作较多的场景下,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获取写锁,独占资源。