MST

星途 面试题库

面试题:Go语言中互斥锁与读写锁的场景选择

在一个Go程序中,有一个数据结构被多个协程访问,其中读操作远多于写操作。请分析在这种场景下,使用互斥锁和读写锁(`sync.RWMutex`)分别有什么优缺点,并举例说明如何正确使用读写锁来优化性能。
22.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

互斥锁优缺点

  • 优点:实现简单,能保证数据的一致性,无论读写操作都能确保同一时间只有一个协程访问数据结构,避免数据竞争。
  • 缺点:由于读写都加锁,在读操作远多于写操作的场景下,读操作会频繁等待锁释放,导致性能下降,因为即使多个读操作同时进行也不会产生数据竞争,但互斥锁会阻止这种并行读。

读写锁(sync.RWMutex)优缺点

  • 优点:区分了读锁和写锁,允许多个读操作同时进行,提高了读操作的并发性能。写操作时会独占锁,防止其他读写操作,保证数据一致性。适合读多写少的场景。
  • 缺点:相比互斥锁实现复杂一些,需要更小心地处理锁的使用,避免死锁。如果写操作频繁,读操作也会因为写锁的独占而等待,性能会受影响。

读写锁使用示例

package main

import (
    "fmt"
    "sync"
)

type Data struct {
    value int
    mu    sync.RWMutex
}

func (d *Data) Read() int {
    d.mu.RLock()
    defer d.mu.RUnlock()
    return d.value
}

func (d *Data) Write(v int) {
    d.mu.Lock()
    defer d.mu.Unlock()
    d.value = v
}

func main() {
    var wg sync.WaitGroup
    data := Data{}

    // 模拟多个读操作
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            fmt.Println("Read:", data.Read())
        }()
    }

    // 模拟写操作
    wg.Add(1)
    go func() {
        defer wg.Done()
        data.Write(42)
    }()

    wg.Wait()
}

在上述示例中,Read 方法使用读锁(RLock),允许多个协程同时读取数据。Write 方法使用写锁(Lock),保证写操作时数据的一致性,其他读写操作都会等待写操作完成。通过这种方式优化了读多写少场景下的性能。