MST

星途 面试题库

面试题:Go中RWMutex锁读写性能平衡基础

在Go语言中,简述RWMutex读锁和写锁的使用场景,为什么读锁允许多个读操作同时进行,而写锁则要独占?请举例说明在读写频繁的场景下如何使用RWMutex来平衡性能。
48.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

RWMutex读锁和写锁的使用场景

  1. 读锁(RLock):适用于只读取共享资源的场景,当多个goroutine同时读取共享资源时,不会造成数据不一致问题,所以允许多个读操作同时进行,这样可以提升并发读的性能。例如在一个存储配置信息的结构体,多个goroutine可能同时需要读取配置,此时使用读锁。
  2. 写锁(Lock):适用于修改共享资源的场景。因为写操作会改变共享资源的状态,如果多个写操作或者读写操作同时进行,会导致数据不一致的问题,所以写锁要独占,保证同一时间只有一个goroutine能进行写操作。比如在更新数据库连接池的连接配置时,需要使用写锁。

读锁允许多个读操作同时进行,写锁要独占的原因

  1. 读操作不改变数据:读操作只是获取数据,多个读操作同时进行不会互相影响,不会导致数据状态的不一致,所以允许多个读操作并发执行以提高效率。
  2. 写操作改变数据:写操作会改变共享资源的状态,如果多个写操作同时进行,会导致最终的数据状态不可预期,读写操作同时进行也可能导致读到“脏数据”,所以写操作需要独占资源,确保数据一致性。

读写频繁场景下使用RWMutex平衡性能示例

package main

import (
    "fmt"
    "sync"
    "time"
)

var (
    data int
    rw   sync.RWMutex
)

func read(id int, wg *sync.WaitGroup) {
    defer wg.Done()
    rw.RLock()
    fmt.Printf("Reader %d reading data: %d\n", id, data)
    rw.RUnlock()
}

func write(id int, wg *sync.WaitGroup) {
    defer wg.Done()
    rw.Lock()
    data = id
    fmt.Printf("Writer %d writing data: %d\n", id, data)
    rw.Unlock()
}

func main() {
    var wg sync.WaitGroup
    // 启动多个读操作
    for i := 1; i <= 3; i++ {
        wg.Add(1)
        go read(i, &wg)
    }
    // 启动多个写操作
    for i := 1; i <= 2; i++ {
        wg.Add(1)
        go write(i, &wg)
    }
    time.Sleep(2 * time.Second)
    wg.Wait()
}

在这个示例中,通过RWMutex的读锁和写锁,在读操作时允许多个goroutine并发读取,而在写操作时保证独占,从而在读写频繁的场景下平衡性能,既保证数据一致性又尽量提高并发效率。