MST

星途 面试题库

面试题:Go语言中读写互斥锁(sync.RWMutex)的读锁和写锁在使用场景上有何区别?

在Go语言的并发编程中,sync.RWMutex提供了读锁(RLock)和写锁(Lock)。请详细阐述在哪些实际场景下适合使用读锁,哪些场景适合使用写锁,并说明原因。同时给出简单示例代码展示两者的使用。
42.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

读锁适用场景及原因

  • 适用场景:当多个并发操作只需要读取共享资源,而不需要对其进行修改时,适合使用读锁。例如在一个Web应用中,多个用户同时请求读取配置文件信息、数据库中的只读数据等场景。
  • 原因:读锁允许多个协程同时获取锁进行读取操作,因为读取操作不会改变共享资源的状态,所以多个读操作之间不会产生数据竞争问题。使用读锁可以提高并发读的效率,充分利用多核CPU的优势,提升系统性能。

写锁适用场景及原因

  • 适用场景:当并发操作需要修改共享资源时,适合使用写锁。比如在银行转账操作中,需要修改账户余额;在更新数据库记录时,都需要使用写锁。
  • 原因:写操作会改变共享资源的状态,如果多个写操作同时进行或者读写操作同时进行,就可能导致数据不一致的问题。写锁是独占锁,当一个协程获取了写锁,其他协程无论是读操作还是写操作都需要等待该写锁释放,这样可以保证在写操作进行时,共享资源不会被其他操作干扰,确保数据的一致性和完整性。

示例代码

package main

import (
    "fmt"
    "sync"
)

var (
    counter int
    mu      sync.RWMutex
)

// 读操作
func read(wg *sync.WaitGroup) {
    defer wg.Done()
    mu.RLock()
    fmt.Printf("Reading: %d\n", counter)
    mu.RUnlock()
}

// 写操作
func write(wg *sync.WaitGroup, val int) {
    defer wg.Done()
    mu.Lock()
    counter = val
    fmt.Printf("Writing: %d\n", counter)
    mu.Unlock()
}

func main() {
    var wg sync.WaitGroup

    // 模拟多个读操作
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go read(&wg)
    }

    // 模拟写操作
    wg.Add(1)
    go write(&wg, 42)

    // 等待所有操作完成
    wg.Wait()
}

在上述代码中,read函数使用读锁进行读取操作,write函数使用写锁进行写操作。通过这种方式,保证了在并发环境下共享资源counter的读写安全。