MST

星途 面试题库

面试题:Go语言中读写锁(sync.RWMutex)在Goroutine并发场景下的应用

假设你有一个应用场景,多个Goroutine会频繁读取一个共享数据结构,但偶尔会有Goroutine对其进行写入操作。请阐述如何使用读写锁(`sync.RWMutex`)来优化这种情况下的并发性能,并给出相应的代码示例,说明读锁和写锁的正确使用方式。
39.6万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
  1. 读写锁优化原理
    • 读写锁(sync.RWMutex)允许有多个读操作同时进行,因为读操作不会改变共享数据结构的状态,不会产生数据竞争。
    • 当有写操作时,为了保证数据的一致性,需要独占访问共享数据结构,此时不能有读操作同时进行。
  2. 代码示例
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(newValue int) {
    d.mu.Lock()
    defer d.mu.Unlock()
    d.value = newValue
}

在上述代码中:

  • Read 方法用于读操作,通过 d.mu.RLock() 获取读锁,这样多个Goroutine可以同时调用 Read 方法读取数据。在方法结束时,通过 defer d.mu.RUnlock() 释放读锁。
  • Write 方法用于写操作,通过 d.mu.Lock() 获取写锁,这会阻止其他读操作和写操作同时进行,保证数据一致性。在方法结束时,通过 defer d.mu.Unlock() 释放写锁。

下面是测试读写操作的示例:

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

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

    // 启动写操作
    wg.Add(1)
    go func() {
        defer wg.Done()
        data.Write(42)
        fmt.Println("Write value: 42")
    }()

    wg.Wait()
}

main 函数中,启动了多个读操作Goroutine和一个写操作Goroutine,通过读写锁保证了并发操作的正确性和性能优化。