MST

星途 面试题库

面试题:Go map在并发场景下的高效使用及注意事项

在并发编程中使用Go的map时,可能会遇到哪些问题?如何解决这些问题以实现高效并发访问?请举例说明使用`sync.Map`和`sync.RWMutex`分别在不同场景下如何确保map的高效并发操作。
19.2万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

在并发编程中使用Go的map时,可能会遇到以下问题:

  1. 竞态条件:多个goroutine同时读写map会导致未定义行为,如数据损坏或程序崩溃。

解决方法及示例:

使用sync.Map

sync.Map是Go标准库提供的线程安全的map实现。适用于高并发读写场景,无需手动加锁。

package main

import (
    "fmt"
    "sync"
)

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

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            key := fmt.Sprintf("key%d", id)
            m.Store(key, id)
            value, ok := m.Load(key)
            if ok {
                fmt.Printf("goroutine %d read value: %d\n", id, value)
            }
        }(i)
    }

    wg.Wait()
}

使用sync.RWMutex

sync.RWMutex用于读写锁控制。当读操作远远多于写操作时,使用读写锁能提高性能。读操作可以并发执行,写操作则需要独占锁。

package main

import (
    "fmt"
    "sync"
)

func main() {
    var mu sync.RWMutex
    m := make(map[string]int)
    var wg sync.WaitGroup

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            key := fmt.Sprintf("key%d", id)
            mu.Lock()
            m[key] = id
            mu.Unlock()
        }(i)
    }

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            key := fmt.Sprintf("key%d", id)
            mu.RLock()
            value, ok := m[key]
            mu.RUnlock()
            if ok {
                fmt.Printf("goroutine %d read value: %d\n", id, value)
            }
        }(i)
    }

    wg.Wait()
}

在这个示例中,写操作使用mu.Lock()获取独占锁,读操作使用mu.RLock()获取读锁,从而确保map在并发操作下的安全。