MST

星途 面试题库

面试题:Go语言在并发复杂场景下的资源竞争处理

在Go语言中,假设你有多个goroutine同时访问和修改共享资源,如一个全局的map,如何使用Go的特性(如sync包相关工具)来避免资源竞争问题?请给出具体的代码示例并解释其原理。
19.8万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

在Go语言中,可以使用sync.Mutex(互斥锁)来避免多个goroutine同时访问和修改共享资源时的资源竞争问题。以下是使用sync.Mutex保护全局map的代码示例:

package main

import (
    "fmt"
    "sync"
)

var (
    globalMap = make(map[string]int)
    mu        sync.Mutex
)

func updateMap(key string, value int, wg *sync.WaitGroup) {
    defer wg.Done()

    mu.Lock()
    globalMap[key] = value
    mu.Unlock()
}

func main() {
    var wg sync.WaitGroup

    keys := []string{"key1", "key2", "key3"}
    values := []int{1, 2, 3}

    for i := range keys {
        wg.Add(1)
        go updateMap(keys[i], values[i], &wg)
    }

    wg.Wait()

    mu.Lock()
    fmt.Println("Final globalMap:", globalMap)
    mu.Unlock()
}

原理解释:

  1. sync.Mutex声明:代码中声明了一个sync.Mutex类型的变量mu。互斥锁的作用是保证在同一时刻只有一个goroutine能够访问被保护的资源。
  2. mu.Lock():在updateMap函数中,通过mu.Lock()来锁定互斥锁。这会阻止其他goroutine同时进入临界区(即修改globalMap的代码段)。如果此时有其他goroutine尝试获取锁,它将被阻塞,直到当前持有锁的goroutine释放锁。
  3. 修改共享资源:在获取锁之后,对globalMap进行修改操作,即globalMap[key] = value
  4. mu.Unlock():修改完成后,通过mu.Unlock()释放锁,允许其他goroutine获取锁并进入临界区进行操作。
  5. sync.WaitGroup:在main函数中,使用sync.WaitGroup来等待所有的goroutine完成操作。wg.Add(1)增加等待组的计数,defer wg.Done()在goroutine结束时减少计数,wg.Wait()阻塞主线程直到所有计数变为0,确保所有对globalMap的修改都已完成。最后,在打印globalMap之前再次获取锁,以保证读取操作的一致性。

这样,通过sync.Mutexsync.WaitGroup,可以有效地避免多个goroutine同时访问和修改共享map时的资源竞争问题。