Golang 程序实现并发哈希映射
并发哈希映射可以被视为确保平稳并行执行的高效数据结构。它旨在高效处理并发读写操作,是构建高性能多线程应用程序的宝贵工具。在本文中,我们学习在 Go 中实现并发哈希映射。
语法
func NewConcurrentMap(size int) *ConcurrentMap
语法定义了一个名为 NewConcurrentMap 的函数,用于创建并返回名为 ConcurrentMap 的自定义并发哈希映射的实例。它采用大小参数来确定数据分发的内部存储桶数,并封装初始化过程。
算法
首先初始化一个固定大小的数组作为哈希映射的底层存储。
实现一个哈希函数,用于将键映射到数组内的索引。
对于每个索引,我们创建单独的链接列表以避免冲突。
定义添加、检索和删除键值对的方法,同时确保同步。
为了使 goroutines 能够同时访问哈希映射的各个部分,最后实现锁定机制,例如互斥锁。
示例 1
在此示例中,为了在 go 中实现并发哈希映射,我们使用 sync.Map() 包和 goroutines,我们直接构建一个并发映射。然后,我们使用空的并发映射,使用 goroutine 并发插入键值对,同时使用同步来确保数据一致性。然后,我们使用并发 goroutine 从映射中检索与键关联的值,以演示线程安全访问。
package main import ( "fmt" "sync" ) func main() { concurrentMap := &sync.Map{} fmt.Println("Step 1: Concurrent Map Created") fmt.Println() var wg sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) go func(index int) { defer wg.Done() key := fmt.Sprintf("key%d", index) value := fmt.Sprintf("value%d", index) concurrentMap.Store(key, value) fmt.Printf("Step 2: Inserted Key: %s, Value: %s\n", key, value) }(i) } wg.Wait() fmt.Println() for i := 0; i < 5; i++ { wg.Add(1) go func(index int) { defer wg.Done() key := fmt.Sprintf("key%d", index) if value, exists := concurrentMap.Load(key); exists { fmt.Printf("Step 3: Retrieved Key: %s, Value: %s\n", key, value) } }(i) } wg.Wait() }
输出
Step 1: Concurrent Map Created Step 2: Inserted Key: key4, Value: value4 Step 2: Inserted Key: key0, Value: value0 Step 2: Inserted Key: key1, Value: value1 Step 2: Inserted Key: key2, Value: value2 Step 2: Inserted Key: key3, Value: value3 Step 3: Retrieved Key: key4, Value: value4 Step 3: Retrieved Key: key0, Value: value0 Step 3: Retrieved Key: key1, Value: value1 Step 3: Retrieved Key: key2, Value: value2 Step 3: Retrieved Key: key3, Value: value3
示例 2
在此示例中,我们新引入了一个自定义并发哈希映射实现,即 ConcurrentMap 类型,每个存储桶都有单独的互斥锁以保持同步。定义的 NewConcurrentMap 函数使用给定数量的存储桶和相应的互斥锁初始化映射。然后使用 Insert 和 Get 方法以及计算出的存储桶索引来控制对映射的访问,锁定和解锁关联的互斥锁,确保线程安全的插入和检索。
package main import ( "fmt" "sync" ) type ConcurrentMap struct { buckets []map[string]string mutexes []sync.Mutex } func NewConcurrentMap(size int) *ConcurrentMap { cm := &ConcurrentMap{make([]map[string]string, size), make([]sync.Mutex, size)} for i := range cm.buckets { cm.buckets[i] = make(map[string]string) } fmt.Println("Step 1: Custom Concurrent Map Created") return cm } func (cm *ConcurrentMap) Insert(key, value string) { index := hash(key) % len(cm.buckets) cm.mutexes[index].Lock() defer cm.mutexes[index].Unlock() cm.buckets[index][key] = value fmt.Printf("Step 2: Inserted Key: %s, Value: %s\n", key, value) } func (cm *ConcurrentMap) Get(key string) (string, bool) { index := hash(key) % len(cm.buckets) cm.mutexes[index].Lock() defer cm.mutexes[index].Unlock() val, exists := cm.buckets[index][key] return val, exists } func hash(key string) int { return len(key) } func main() { concurrentMap := NewConcurrentMap(10) fmt.Println() var wg sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) go func(index int) { defer wg.Done(); key, value := fmt.Sprintf("key%d", index), fmt.Sprintf("value%d", index); concurrentMap.Insert(key, value) }(i) } wg.Wait() fmt.Println() for i := 0; i < 5; i++ { wg.Add(1) go func(index int) { defer wg.Done(); key := fmt.Sprintf("key%d", index); if value, exists := concurrentMap.Get(key); exists { fmt.Printf("Step 3: Retrieved Key: %s, Value: %s\n", key, value) } }(i) } wg.Wait() }
输出
Step 1: Custom Concurrent Map Created Step 2: Inserted Key: key4, Value: value4 Step 2: Inserted Key: key0, Value: value0 Step 2: Inserted Key: key1, Value: value1 Step 2: Inserted Key: key2, Value: value2 Step 2: Inserted Key: key3, Value: value3 Step 3: Retrieved Key: key4, Value: value4 Step 3: Retrieved Key: key0, Value: value0 Step 3: Retrieved Key: key1, Value: value1 Step 3: Retrieved Key: key2, Value: value2 Step 3: Retrieved Key: key3, Value: value3
实际实施
抄袭检测:哈希图用于抄袭检测系统,以存储从文档中获取的短语或文本块的哈希值。此功能可以轻松比较和识别相同或难以区分的数据,从而帮助检测疑似抄袭的情况。
社交媒体关注者系统:考虑一个类似的社交媒体网络,如 Instagram。该平台使用哈希图来管理关注者和与每个用户关联的关注者。单击用户个人资料上的"关注"按钮,会立即更新哈希图,从而在唯一用户 ID 和选择关注的人的用户 ID 之间建立连接。这样可以轻松检索某人的关注者以及被关注者,从而提高 feed 的个性化程度。
结论
并发哈希映射是现代并行编程中的关键数据结构,允许多个线程同时访问和修改数据,同时保持同步。在本文中,我们通过两种不同的方法详细阐述了实现并发哈希映射的概念。第一种方法使用内置的 sync.Map 类型动态处理同步,并且对于涉及多个线程或 goroutine 的场景非常有效。下一种自定义实现方法提供了对同步的细粒度控制,允许显式管理并发并提供对同步过程的洞察。