MST

星途 面试题库

面试题:Go语言中使用Mutex构建线程安全的Map数据结构

在Go语言中,原生的`map`不是线程安全的。请你基于`Mutex`实现一个线程安全的`SafeMap`结构体,该结构体需要提供`Set`(设置键值对)、`Get`(获取值)和`Delete`(删除键值对)方法。并且需要考虑在高并发情况下,如何优化锁的粒度以提高性能。
30.0万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试
package main

import (
    "sync"
)

// SafeMap 线程安全的map结构体
type SafeMap struct {
    mu sync.RWMutex
    data map[interface{}]interface{}
}

// NewSafeMap 创建一个新的SafeMap实例
func NewSafeMap() *SafeMap {
    return &SafeMap{
        data: make(map[interface{}]interface{}),
    }
}

// Set 设置键值对
func (sm *SafeMap) Set(key, value interface{}) {
    sm.mu.Lock()
    defer sm.mu.Unlock()
    sm.data[key] = value
}

// Get 获取值
func (sm *SafeMap) Get(key interface{}) (interface{}, bool) {
    sm.mu.RLock()
    defer sm.mu.RUnlock()
    value, exists := sm.data[key]
    return value, exists
}

// Delete 删除键值对
func (sm *SafeMap) Delete(key interface{}) {
    sm.mu.Lock()
    defer sm.mu.Unlock()
    delete(sm.data, key)
}

优化锁粒度以提高性能

  1. 分段锁:可以将SafeMap中的数据按一定规则(比如哈希值范围)分成多个段,每个段有自己独立的锁。这样不同段的操作可以并发进行,减少锁竞争。
  2. 读写锁分离:在SafeMap的实现中已经使用了读写锁(sync.RWMutex),读操作可以并发执行,只有写操作需要独占锁。在高读低写的场景下,这种方式能显著提升性能。
// 示例分段锁实现
const numBuckets = 16

type Bucket struct {
    mu sync.RWMutex
    data map[interface{}]interface{}
}

type SegmentSafeMap struct {
    buckets [numBuckets]Bucket
}

func NewSegmentSafeMap() *SegmentSafeMap {
    ssm := &SegmentSafeMap{}
    for i := range ssm.buckets {
        ssm.buckets[i].data = make(map[interface{}]interface{})
    }
    return ssm
}

func (ssm *SegmentSafeMap) hashKey(key interface{}) int {
    // 简单的哈希函数示例,实际应用中可优化
    switch k := key.(type) {
    case int:
        return k % numBuckets
    case string:
        hash := 0
        for _, char := range k {
            hash = 31*hash + int(char)
        }
        return hash % numBuckets
    default:
        return 0
    }
}

func (ssm *SegmentSafeMap) Set(key, value interface{}) {
    index := ssm.hashKey(key)
    ssm.buckets[index].mu.Lock()
    defer ssm.buckets[index].mu.Unlock()
    ssm.buckets[index].data[key] = value
}

func (ssm *SegmentSafeMap) Get(key interface{}) (interface{}, bool) {
    index := ssm.hashKey(key)
    ssm.buckets[index].mu.RLock()
    defer ssm.buckets[index].mu.RUnlock()
    value, exists := ssm.buckets[index].data[key]
    return value, exists
}

func (ssm *SegmentSafeMap) Delete(key interface{}) {
    index := ssm.hashKey(key)
    ssm.buckets[index].mu.Lock()
    defer ssm.buckets[index].mu.Unlock()
    delete(ssm.buckets[index].data, key)
}