MST

星途 面试题库

面试题:Go多维切片在并发场景下的一致性问题

假设你正在开发一个基于Go的高并发应用,其中涉及到对一个二维切片进行频繁的读写操作。在并发环境下,如何确保对该二维切片的读写操作的一致性,避免数据竞争和不一致问题?请详细描述你的解决方案,包括使用到的同步机制,并给出完整的代码示例。
26.9万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

在Go语言中,可以使用sync.Mutexsync.RWMutex来确保对二维切片的读写操作的一致性,避免数据竞争和不一致问题。以下是两种解决方案:

使用sync.Mutex

sync.Mutex提供了一种简单的互斥锁机制,用于保护共享资源。在对二维切片进行读写操作时,需要先获取锁,操作完成后释放锁。

package main

import (
    "fmt"
    "sync"
)

var (
    twoDSlice [][]int
    mu        sync.Mutex
)

func writeData(data [][]int) {
    mu.Lock()
    twoDSlice = data
    mu.Unlock()
}

func readData() [][]int {
    mu.Lock()
    defer mu.Unlock()
    return twoDSlice
}

func main() {
    var wg sync.WaitGroup

    // 模拟写操作
    wg.Add(1)
    go func() {
        defer wg.Done()
        writeData([][]int{{1, 2}, {3, 4}})
    }()

    // 模拟读操作
    wg.Add(1)
    go func() {
        defer wg.Done()
        result := readData()
        fmt.Println(result)
    }()

    wg.Wait()
}

使用sync.RWMutex

sync.RWMutex提供了读写锁机制,允许多个读操作同时进行,但写操作必须独占。这种方式在读取操作频繁而写入操作较少的情况下性能更好。

package main

import (
    "fmt"
    "sync"
)

var (
    twoDSlice [][]int
    rwMu      sync.RWMutex
)

func writeData(data [][]int) {
    rwMu.Lock()
    twoDSlice = data
    rwMu.Unlock()
}

func readData() [][]int {
    rwMu.RLock()
    defer rwMu.RUnlock()
    return twoDSlice
}

func main() {
    var wg sync.WaitGroup

    // 模拟写操作
    wg.Add(1)
    go func() {
        defer wg.Done()
        writeData([][]int{{1, 2}, {3, 4}})
    }()

    // 模拟读操作
    wg.Add(1)
    go func() {
        defer wg.Done()
        result := readData()
        fmt.Println(result)
    }()

    wg.Wait()
}

在上述代码中:

  1. writeData函数在写入二维切片时,先获取锁(mu.Lock()rwMu.Lock()),操作完成后释放锁(mu.Unlock()rwMu.Unlock())。
  2. readData函数在读取二维切片时,获取读锁(rwMu.RLock()),操作完成后释放读锁(rwMu.RUnlock())。如果使用sync.Mutex,则和写操作一样获取普通锁。
  3. main函数中,通过go关键字启动多个并发的读写操作,并使用sync.WaitGroup等待所有操作完成。

这两种方法都能有效地避免数据竞争和不一致问题,具体使用哪种方法取决于应用场景中读写操作的频率。如果读操作远多于写操作,建议使用sync.RWMutex;如果读写操作频率相近,使用sync.Mutex即可。