MST

星途 面试题库

面试题:Go并发编程中资源竞争的常见场景及规避方法

在Go并发编程里,资源竞争是一个常见误区。请列举至少两种可能导致资源竞争的场景,并说明如何使用Go语言提供的工具(如sync包)来规避这些问题。
34.8万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

可能导致资源竞争的场景:

  1. 多个 goroutine 同时读写共享变量:例如多个 goroutine 同时对一个全局变量进行读写操作,读操作和写操作没有顺序控制,就可能出现读操作读取到部分写入的数据,导致数据不一致。
  2. 对共享的 map 进行并发读写:Go 语言的 map 本身不是线程安全的,多个 goroutine 同时对一个 map 进行读和写,或者同时进行多个写操作,可能导致程序崩溃或者数据混乱。

规避方法:

  1. 使用 sync.Mutex
    • 原理sync.Mutex 是一种互斥锁,它可以保证在同一时刻只有一个 goroutine 能够访问共享资源。
    • 示例
package main

import (
    "fmt"
    "sync"
)

var (
    count int
    mu    sync.Mutex
)

func increment(wg *sync.WaitGroup) {
    defer wg.Done()
    mu.Lock()
    count++
    mu.Unlock()
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go increment(&wg)
    }
    wg.Wait()
    fmt.Println("Final count:", count)
}
  1. 使用 sync.RWMutex
    • 原理sync.RWMutex 是读写互斥锁,允许多个 goroutine 同时进行读操作,但只允许一个 goroutine 进行写操作。当有写操作时,其他读和写操作都被阻塞。
    • 示例
package main

import (
    "fmt"
    "sync"
)

var (
    data  = make(map[string]string)
    rwmu  sync.RWMutex
)

func read(key string, wg *sync.WaitGroup) {
    defer wg.Done()
    rwmu.RLock()
    value := data[key]
    fmt.Printf("Read key %s, value %s\n", key, value)
    rwmu.RUnlock()
}

func write(key, value string, wg *sync.WaitGroup) {
    defer wg.Done()
    rwmu.Lock()
    data[key] = value
    fmt.Printf("Write key %s, value %s\n", key, value)
    rwmu.Unlock()
}

func main() {
    var wg sync.WaitGroup
    wg.Add(2)
    go write("name", "John", &wg)
    go read("name", &wg)
    wg.Wait()
}
  1. 使用 sync.Map
    • 原理sync.Map 是 Go 语言提供的线程安全的 map 实现,它内部使用了类似分段锁的机制,允许多个 goroutine 并发地进行读写操作。
    • 示例
package main

import (
    "fmt"
    "sync"
)

func main() {
    var m sync.Map
    var wg sync.WaitGroup
    wg.Add(2)

    go func() {
        defer wg.Done()
        m.Store("name", "John")
    }()

    go func() {
        defer wg.Done()
        value, ok := m.Load("name")
        if ok {
            fmt.Printf("Load key name, value %s\n", value.(string))
        }
    }()

    wg.Wait()
}