MST

星途 面试题库

面试题:Go中如何通过读写锁优化读多写少场景下的性能

假设你正在开发一个Go程序,该程序在并发环境下读操作远远多于写操作。请详细说明如何使用读写锁(`sync.RWMutex`)来优化性能,包括读写锁的原理、使用方式以及与普通互斥锁(`sync.Mutex`)相比的优势。
26.7万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

读写锁原理

sync.RWMutex 是Go语言标准库提供的读写锁。其原理基于读操作可以并发执行,而写操作必须独占资源。读写锁有两种模式:读模式和写模式。

  • 读模式:多个读操作可以同时进行,因为读操作不会修改共享资源,所以不会产生数据竞争。
  • 写模式:写操作必须是独占的,当一个写操作在进行时,不允许其他读操作或写操作进行,以确保数据的一致性。

使用方式

以下是一个简单的示例代码,展示如何在Go中使用 sync.RWMutex

package main

import (
    "fmt"
    "sync"
)

var (
    data int
    rwmu sync.RWMutex
)

func read(wg *sync.WaitGroup) {
    defer wg.Done()
    rwmu.RLock()
    fmt.Printf("Read data: %d\n", data)
    rwmu.RUnlock()
}

func write(wg *sync.WaitGroup, value int) {
    defer wg.Done()
    rwmu.Lock()
    data = value
    fmt.Printf("Write data: %d\n", data)
    rwmu.Unlock()
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go read(&wg)
    }
    for i := 0; i < 2; i++ {
        wg.Add(1)
        go write(&wg, i*10)
    }
    wg.Wait()
}

在上述代码中:

  • read 函数使用 rwmu.RLock() 来获取读锁,允许多个读操作并发执行。操作完成后使用 rwmu.RUnlock() 释放读锁。
  • write 函数使用 rwmu.Lock() 来获取写锁,写操作完成后使用 rwmu.Unlock() 释放写锁。写锁是独占的,获取写锁时不允许其他读写操作。

与普通互斥锁相比的优势

  • 性能提升:在读写比例悬殊(读多写少)的场景下,读写锁允许并发读操作,大大提高了程序的并发性能。而普通互斥锁(sync.Mutex)无论读写都只允许一个操作进行,读操作也会被阻塞,导致性能瓶颈。
  • 资源利用率:读写锁能更好地利用系统资源,因为读操作不需要等待其他读操作完成,可以同时进行。而普通互斥锁会使读操作串行化,降低了资源利用率。