MST

星途 面试题库

面试题:Go语言使用sync.Map实现复杂场景的并发安全

假设你有一个场景,需要在多个goroutine中频繁地对Map进行读取、写入和删除操作,同时还要统计Map中不同类型数据的数量。请使用Go语言的sync.Map来设计并实现这个功能,描述设计思路并写出完整代码。
38.5万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 使用sync.Map来处理多个goroutine的并发读写操作,因为sync.Map是线程安全的,适合这种场景。
  2. 为了统计不同类型数据的数量,我们可以使用另一个sync.Map来存储每种类型数据的计数。
  3. 对于数据的读取、写入和删除操作,我们分别定义对应的函数,在这些函数中对sync.Map进行操作,并同时更新类型计数的sync.Map

完整代码

package main

import (
	"fmt"
	"sync"
)

// Data 用于存储不同类型的数据
type Data struct {
	value interface{}
}

func main() {
	var wg sync.WaitGroup
	mainMap := sync.Map{}
	typeCountMap := sync.Map{}

	// 模拟多个goroutine进行操作
	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			// 写入操作
			writeData(&mainMap, &typeCountMap, Data{value: fmt.Sprintf("string-%d", id)})
			// 读取操作
			readData(&mainMap, fmt.Sprintf("string-%d", id))
			// 删除操作
			deleteData(&mainMap, &typeCountMap, fmt.Sprintf("string-%d", id))
		}(i)
	}

	wg.Wait()

	// 输出每种类型数据的数量
	typeCountMap.Range(func(key, value interface{}) bool {
		fmt.Printf("Type %v count: %v\n", key, value)
		return true
	})
}

// writeData 写入数据到mainMap,并更新typeCountMap
func writeData(mainMap *sync.Map, typeCountMap *sync.Map, data Data) {
	mainMap.Store(data.value, data)
	typeKey := fmt.Sprintf("%T", data.value)
	typeCountMap.Store(typeKey, getTypeCount(typeCountMap, typeKey)+1)
}

// readData 从mainMap读取数据
func readData(mainMap *sync.Map, key interface{}) {
	value, ok := mainMap.Load(key)
	if ok {
		fmt.Printf("Read data: %v\n", value)
	} else {
		fmt.Printf("Data with key %v not found\n", key)
	}
}

// deleteData 从mainMap删除数据,并更新typeCountMap
func deleteData(mainMap *sync.Map, typeCountMap *sync.Map, key interface{}) {
	mainMap.Delete(key)
	typeKey := fmt.Sprintf("%T", key)
	count := getTypeCount(typeCountMap, typeKey)
	if count > 0 {
		typeCountMap.Store(typeKey, count-1)
	}
}

// getTypeCount 获取typeCountMap中指定类型的计数
func getTypeCount(typeCountMap *sync.Map, typeKey string) int {
	value, ok := typeCountMap.Load(typeKey)
	if ok {
		return value.(int)
	}
	return 0
}