亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Go語言如何實(shí)現(xiàn)線程安全的Map

 更新時(shí)間:2024年11月26日 09:09:30   作者:熬了夜的程序員  
Go語言內(nèi)置的map雖然高效,但并不是線程安全的,若在多線程環(huán)境中直接操作map,可能會(huì)引發(fā)并發(fā)寫入的錯(cuò)誤,下面我們就來看看如何實(shí)現(xiàn)線程安全的Map吧

在并發(fā)編程中,數(shù)據(jù)共享和訪問是一個(gè)重要的主題。Go語言內(nèi)置的map雖然高效,但并不是線程安全的。若在多線程環(huán)境中直接操作map,可能會(huì)引發(fā)并發(fā)寫入的錯(cuò)誤(fatal error: concurrent map writes)。因此,在需要并發(fā)訪問map時(shí),必須采取措施確保線程安全。

本文將介紹如何使用Go語言的泛型和sync.RWMutex實(shí)現(xiàn)一個(gè)線程安全的Map,同時(shí)支持常見的操作,例如增刪改查、遍歷和轉(zhuǎn)化為普通的Map。

1. 為什么需要線程安全的Map

Go語言內(nèi)置的map在多線程環(huán)境中并不安全。例如,以下代碼可能引發(fā)崩潰:

package main

import (
	"fmt"
	"sync"
)

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

	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func(i int) {
			defer wg.Done()
			m[i] = i
		}(i)
	}

	wg.Wait()
	fmt.Println(m)
}

運(yùn)行上述代碼可能會(huì)報(bào)錯(cuò):fatal error: concurrent map writes。這是因?yàn)閙ap的寫操作沒有加鎖,在多線程中引發(fā)了競(jìng)態(tài)條件。

2. 如何實(shí)現(xiàn)線程安全的Map

Go標(biāo)準(zhǔn)庫(kù)提供了sync.Map,它是線程安全的。但它的API相對(duì)簡(jiǎn)單,缺乏泛型支持且性能在某些場(chǎng)景下并不理想。因此,我們可以基于sync.RWMutex和泛型封裝一個(gè)自定義的線程安全Map。

2.1 基本實(shí)現(xiàn)

以下是線程安全SyncMap的完整實(shí)現(xiàn):

package syncmap

import (
	"sync"
)

// SyncMap 定義了一個(gè)線程安全的泛型Map
type SyncMap[K comparable, V any] struct {
	mu sync.RWMutex
	m  map[K]V
}

// NewSyncMap 創(chuàng)建一個(gè)新的線程安全的SyncMap
func NewSyncMap[K comparable, V any]() *SyncMap[K, V] {
	return &SyncMap[K, V]{
		m: make(map[K]V),
	}
}

// Load 獲取指定key的值,如果存在返回值和true,否則返回零值和false
func (s *SyncMap[K, V]) Load(key K) (V, bool) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	val, ok := s.m[key]
	return val, ok
}

// Store 設(shè)置指定key的值,如果key已存在會(huì)覆蓋舊值
func (s *SyncMap[K, V]) Store(key K, value V) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.m[key] = value
}

// Has returns true if the key exists in the map.
func (s *SyncMap[K, V]) Has(key K) bool {
	s.mu.RLock()
	defer s.mu.RUnlock()

	_, ok := s.m[key]
	return ok
}


// Delete 刪除指定key的值
func (s *SyncMap[K, V]) Delete(key K) {
	s.mu.Lock()
	defer s.mu.Unlock()
	delete(s.m, key)
}

// Range 遍歷所有的鍵值對(duì),callback函數(shù)返回false時(shí)停止遍歷
func (s *SyncMap[K, V]) Range(callback func(key K, value V) bool) {
	s.mu.RLock()
	defer s.mu.RUnlock()
	for k, v := range s.m {
		if !callback(k, v) {
			break
		}
	}
}

// Len returns the length of the map.
func (s *SyncMap[K, V]) Len() int {
	s.mu.RLock()
	defer s.mu.RUnlock()
	return len(s.m)
}

// ToMap 轉(zhuǎn)化為普通的map,返回一個(gè)線程安全的副本
func (s *SyncMap[K, V]) ToMap() map[K]V {
	s.mu.RLock()
	defer s.mu.RUnlock()

	copyMap := make(map[K]V, len(s.m))
	for k, v := range s.m {
		copyMap[k] = v
	}
	return copyMap
}

2.2 關(guān)鍵功能說明

線程安全:

  • 讀操作使用sync.RWMutex的RLock,允許并發(fā)讀取。
  • 寫操作使用sync.RWMutex的Lock,確保寫操作互斥。

支持泛型:

通過K和V泛型參數(shù)支持任意鍵值類型,其中K必須是可比較的。

基本操作:

  • Load:獲取值。
  • Store:設(shè)置值。
  • Has:判斷鍵是否存在。
  • Delete:刪除鍵值對(duì)。
  • Range:遍歷所有鍵值對(duì)。
  • Len:獲取map的長(zhǎng)度。
  • ToMap:轉(zhuǎn)化為普通map。

3. 使用示例

以下代碼演示了SyncMap的基本用法:

package main

import (
	"fmt"
	"syncmap"
)

func main() {
	// 創(chuàng)建一個(gè)線程安全的Map
	m := syncmap.NewSyncMap[string, int]()

	// 添加值
	m.Store("one", 1)
	m.Store("two", 2)

	// 獲取值
	if val, ok := m.Load("one"); ok {
		fmt.Println("Key 'one':", val)
	} else {
		fmt.Println("Key 'one' not found")
	}

	// 刪除值
	m.Delete("one")

	// 遍歷所有鍵值對(duì)
	m.Range(func(key string, value int) bool {
		fmt.Printf("Key: %s, Value: %d
", key, value)
		return true
	})

	// 轉(zhuǎn)化為普通map
	ordinaryMap := m.ToMap()
	fmt.Println("Ordinary map:", ordinaryMap)
}

運(yùn)行結(jié)果:

Key 'one': 1
Key: two, Value: 2
Ordinary map: map[two:2]

4. 總結(jié)

自定義線程安全的SyncMap具備以下優(yōu)點(diǎn):

  • 泛型支持:靈活適配不同類型的鍵值。
  • 線程安全:支持高并發(fā)場(chǎng)景的安全訪問。
  • 可擴(kuò)展性:易于添加更多功能,如合并操作、條件更新等。

通過本文的實(shí)現(xiàn)與示例,希望您能更好地理解和應(yīng)用線程安全Map,構(gòu)建健壯的并發(fā)應(yīng)用。

到此這篇關(guān)于Go語言如何實(shí)現(xiàn)線程安全的Map的文章就介紹到這了,更多相關(guān)Go線程安全Map內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang 讀取并解析SQL文件的實(shí)現(xiàn)方法

    Golang 讀取并解析SQL文件的實(shí)現(xiàn)方法

    本文介紹了如何使用Go語言編寫一個(gè)簡(jiǎn)單的函數(shù),用于讀取并解析SQL文件,通過一個(gè)函數(shù),我們可以輕松地將SQL文件中的語句提取出來,進(jìn)行后續(xù)的操作,感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • 基于context.Context的Golang?loader緩存請(qǐng)求放大問題解決

    基于context.Context的Golang?loader緩存請(qǐng)求放大問題解決

    這篇文章主要為大家介紹了基于context.Context的Golang?loader緩存請(qǐng)求放大解決方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • golang代碼中調(diào)用Linux命令

    golang代碼中調(diào)用Linux命令

    本文主要介紹了golang代碼中調(diào)用Linux命令,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • Go 面向包新提案透明文件夾必要性分析

    Go 面向包新提案透明文件夾必要性分析

    這篇文章主要為大家介紹了Go 面向包新提案,透明文件夾必要性分析,看看是否合適加進(jìn) Go 特性中,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • 搭建Go語言的ORM框架Gorm的具體步驟(從Java到go)

    搭建Go語言的ORM框架Gorm的具體步驟(從Java到go)

    很多朋友不知道如何使用Goland軟件,搭建一個(gè)ORM框架GORM,今天小編給大家分享一篇教程關(guān)于搭建Go語言的ORM框架Gorm的具體步驟(從Java到go),感興趣的朋友跟隨小編一起學(xué)習(xí)下吧
    2022-09-09
  • Golang網(wǎng)絡(luò)模型netpoll源碼解析(具體流程)

    Golang網(wǎng)絡(luò)模型netpoll源碼解析(具體流程)

    本文介紹了Golang的網(wǎng)絡(luò)模型netpoll的實(shí)現(xiàn)原理,本文將從為什么需要使用netpoll模型,以及netpoll的具體流程實(shí)現(xiàn)兩個(gè)主要角度來展開學(xué)習(xí),感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • Golang中crypto/rand庫(kù)的使用技巧與最佳實(shí)踐

    Golang中crypto/rand庫(kù)的使用技巧與最佳實(shí)踐

    在Golang的眾多隨機(jī)數(shù)生成庫(kù)中,crypto/rand?是一個(gè)專為加密安全設(shè)計(jì)的庫(kù),本文主要介紹了Golang中crypto/rand庫(kù)的使用技巧與最佳實(shí)踐,感興趣的可以了解一下
    2024-02-02
  • Golang實(shí)現(xiàn)簡(jiǎn)易的命令行功能

    Golang實(shí)現(xiàn)簡(jiǎn)易的命令行功能

    這篇文章主要為大家詳細(xì)介紹了如何通過Golang實(shí)現(xiàn)一個(gè)簡(jiǎn)易的命令行功能,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的可以了解一下
    2023-02-02
  • Golang指針隱式間接引用詳解

    Golang指針隱式間接引用詳解

    在 Go中,指針隱式解引用是指通過指針直接訪問指針?biāo)赶虻闹?,而不需要顯式地使用 * 運(yùn)算符來解引用指針,這篇文章主要介紹了Golang指針隱式間接引用,需要的朋友可以參考下
    2023-05-05
  • go中make用法及常見的一些坑

    go中make用法及常見的一些坑

    golang分配內(nèi)存主要有內(nèi)置函數(shù)new和make,下面這篇文章主要給大家介紹了關(guān)于go中make用法及常見的一些坑,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12

最新評(píng)論