最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go實現(xiàn)map并發(fā)安全的3種方式總結(jié)

 更新時間:2023年10月08日 11:14:51   作者:好像、下雨了  
Go的原生map不是并發(fā)安全的,在多協(xié)程讀寫同一個map的時候,安全性無法得到保障,這篇文章主要給大家總結(jié)介紹了關(guān)于Go實現(xiàn)map并發(fā)安全的3種方式,需要的朋友可以參考下

實現(xiàn)map并發(fā)讀寫線程安全

1. 加鎖

對整個map加上讀寫鎖sync.RWMutex

//keyType為key的類型,valueType為value的類型
type RWMap struct {
	Map map[keyType]valueType
	sync.RWMutex
}
func NewRWMap(capacity int) *RWMap {
	if capacity < 0 {
		capacity = 0
	}
	return &RWMap{
		Map: make(map[keyType]valueType, capacity),
	}
}
//add or update
func (m *RWMap) Set(key keyType, value valueType) {
	m.Lock()
	defer m.Unlock()
	m.Map[key] = value
}
//delete
func (m *RWMap) Delete(key int)  {
	m.Lock()
	defer m.Unlock()
	delete(m.Map, key)
}
//get
func (m *RWMap) Get(key int) valueType {
	m.RLock()
	defer m.RUnlock()
	return m.Map[key]
}

優(yōu)點:解決了問題。

缺點:鎖粒度大。

2. 分片加鎖

一個操作會導(dǎo)致整個map被鎖住,導(dǎo)致性能降低。所以提出了分片思想,將一個map分成幾個片,按片加鎖。

第三方包實現(xiàn):github.com/orcaman/concurrent-map

github上用 map language:go 搜索:

3.4kstar

插曲:注意,如果你的goland ide 版本太老的話,github.com/orcaman/concurrent-map/v2 版本是用不了的:

所以我最后換成VSCode,發(fā)現(xiàn)就沒這個問題了。(因為新版本的GoLand還得繼續(xù)想法子破解)

源碼New方法返回的map,看到key只支持string

// Creates a new concurrent map.
func New[V any]() ConcurrentMap[string, V] {
	return create[string, V](fnv32)
}

Example and usage

package main
import (
	"fmt"
	"time"
	cmap "github.com/orcaman/concurrent-map/v2"
)
func main() {
	m := cmap.New[int]()
	for i := 0; i < 300; i++ {
		go func(i int) {
			m.Set(fmt.Sprintf("%v", i), i*2)  //并發(fā)寫
		}(i)
	}
	time.Sleep(4 * time.Second)
	fmt.Println(len(m.Keys()))
}

execute and output:

PS C:\GoWork\src\asset-manager\mytest> go run main.go
300

并發(fā)寫沒問題。

更多使用示例包里的concurrent_map_test.go里面提供了。

3. sync.Map

標準庫中的 sync.Map是專為 append-only 場景設(shè)計的。

sync.Map在讀多寫少性能比較好,否則并發(fā)性能很差。

Go源碼:

// Map is like a Go map[interface{}]interface{} but is safe for concurrent use
// by multiple goroutines without additional locking or coordination. 
// Loads, stores, and deletes run in amortized constant time. 
//=====自注釋======
sync.Map 很像Go map[interface{}]interface{}。但sync.Map是線程安全的,能被多個協(xié)程在沒有額外的鎖或者協(xié)調(diào)的情況下并發(fā)使用。
Loads,stores,deletes操作都運行在分攤常數(shù)時間內(nèi)。
amortized 平攤的(adj.)英  /??m??ta?zd/
//=====自注釋======
//
// The Map type is specialized. Most code should use a plain Go map instead,
// with separate locking or coordination, for better type safety and to make it
// easier to maintain other invariants along with the map content.
//=====自注釋======
invariants (n.) 不變量(invariant的復(fù)數(shù))/?n?veri?nts/
sync.Map 類型是為特殊情況專門設(shè)計的。
大多數(shù)代碼都應(yīng)該使用普通的Go map + 單獨的鎖或者協(xié)調(diào) ,這種形式,來獲得更好的類型安全
以及使得在維護映射內(nèi)容的同時維護其他不變量更容易。
//=====自注釋======
//
// The Map type is optimized for two common use cases: (1) when the entry for a given
// key is only ever written once but read many times, as in caches that only grow,
// or (2) when multiple goroutines read, write, and overwrite entries for disjoint
// sets of keys. In these two cases, use of a Map may significantly reduce lock
// contention compared to a Go map paired with a separate Mutex or RWMutex.
//=====自注釋======
disjoint (adj.) 不連貫的,(兩個集合)不相交的 /d?s?d???nt/
sync.Map類型針對兩個常見用例進行了優(yōu)化:
(1)對于一個給定的key,只會寫一次,但是讀很多次,就像在只增長的緩存中一樣。
(2)當(dāng)多個協(xié)程讀,寫,重寫不相交的keys。
以上兩種情況,相比于使用Go map + Mutex(或者RWMutex),使用sync.Map能顯著減少鎖競爭。
//=====自注釋======
//
// The zero Map is empty and ready for use. A Map must not be copied after first use.
type Map struct {
	mu Mutex
	// read contains the portion of the map's contents that are safe for
	// concurrent access (with or without mu held).
	//
	// The read field itself is always safe to load, but must only be stored with
	// mu held.
	//
	// Entries stored in read may be updated concurrently without mu, but updating
	// a previously-expunged entry requires that the entry be copied to the dirty
	// map and unexpunged with mu held.
	read atomic.Value // readOnly
	// dirty contains the portion of the map's contents that require mu to be
	// held. To ensure that the dirty map can be promoted to the read map quickly,
	// it also includes all of the non-expunged entries in the read map.
//=====自注釋======
expunged (adj.)/?k?sp?nd?/ 被擦去的,被刪掉的
dirty map 包含map內(nèi)容的部分,該部分要求持有mu鎖。為了確保dirty map能快速提升到read map,
它還包括read map 中所有未刪除的項。
//=====自注釋======
	//
	// Expunged entries are not stored in the dirty map. An expunged entry in the
	// clean map must be unexpunged and added to the dirty map before a new value
	// can be stored to it.
	//
	// If the dirty map is nil, the next write to the map will initialize it by
	// making a shallow copy of the clean map, omitting stale entries.
	dirty map[any]*entry
	// misses counts the number of loads since the read map was last updated that
	// needed to lock mu to determine whether the key was present.
	//
	// Once enough misses have occurred to cover the cost of copying the dirty
	// map, the dirty map will be promoted to the read map (in the unamended
	// state) and the next store to the map will make a new dirty copy.
	misses int
}

read atomic.Value

sync/stomic包里都是go提供的原子操作。

sync.Map思想:就是用兩個數(shù)據(jù)結(jié)構(gòu)(只讀的 read 和可寫的 dirty)盡量將讀寫操作分開,并最小粒度加鎖,來減少鎖對性能的影響。

總結(jié)

較常使用的是前兩種:加讀寫鎖和分片加鎖。特定場景下sync.Map性能會有更優(yōu)的表現(xiàn)(要滿足那兩個場景條件比較苛刻,實際很少用)。

相關(guān)文章

  • 在Visual Studio Code中配置GO開發(fā)環(huán)境的詳細教程

    在Visual Studio Code中配置GO開發(fā)環(huán)境的詳細教程

    這篇文章主要介紹了在Visual Studio Code中配置GO開發(fā)環(huán)境的詳細教程,需要的朋友可以參考下
    2017-02-02
  • Go日志之日志庫講解

    Go日志之日志庫講解

    本文介紹了Go語言中最優(yōu)秀的日志庫,包括Zap、log/slog、Logrus和Zerolog,它們都提供了結(jié)構(gòu)化日志記錄、自定義日志級別、輸出目標等特性,感興趣的可以了解一下
    2026-04-04
  • Go語言入門學(xué)習(xí)之Channel通道詳解

    Go語言入門學(xué)習(xí)之Channel通道詳解

    go routine可以使用channel來進行通信,使用通信的手段來共享內(nèi)存,下面這篇文章主要給大家介紹了關(guān)于Go語言入門學(xué)習(xí)之Channel通道的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-07-07
  • 使用Golang實現(xiàn)AES加解密的代碼示例

    使用Golang實現(xiàn)AES加解密的代碼示例

    在現(xiàn)代的數(shù)據(jù)安全中,加密和解密是極其重要的一環(huán),其中,高級加密標準(AES)是最廣泛使用的加密算法之一,本文將介紹如何使用Golang來實現(xiàn)AES加密和解密,需要的朋友可以參考下
    2024-04-04
  • 基于go手動寫個轉(zhuǎn)發(fā)代理服務(wù)的代碼實現(xiàn)

    基于go手動寫個轉(zhuǎn)發(fā)代理服務(wù)的代碼實現(xiàn)

    這篇文章主要介紹了基于go手動寫個轉(zhuǎn)發(fā)代理服務(wù)的代碼實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • 詳解如何使用Golang擴展Envoy

    詳解如何使用Golang擴展Envoy

    這篇文章主要為大家介紹了詳解如何使用Golang擴展Envoy實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • 一文帶你熟悉Go語言中的分支結(jié)構(gòu)

    一文帶你熟悉Go語言中的分支結(jié)構(gòu)

    這篇文章主要和大家分享一下Go語言中的分支結(jié)構(gòu)(if?-?else-if?-?else、switch),文中的示例代碼講解詳細,對我們學(xué)習(xí)Go語言有一定的幫助,需要的可以參考一下
    2022-11-11
  • Go Map并發(fā)沖突預(yù)防與解決

    Go Map并發(fā)沖突預(yù)防與解決

    這篇文章主要為大家介紹了Go Map并發(fā)沖突預(yù)防與解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • 一文徹底理解Golang閉包實現(xiàn)原理

    一文徹底理解Golang閉包實現(xiàn)原理

    閉包對于一個長期寫Java的開發(fā)者來說估計鮮有耳聞,光這名字感覺就有點"神秘莫測"。這篇文章的主要目的就是從編譯器的角度來分析閉包,徹底搞懂閉包的實現(xiàn)原理,需要的可以參考一下
    2022-10-10
  • 深入了解Go的interface{}底層原理實現(xiàn)

    深入了解Go的interface{}底層原理實現(xiàn)

    本文主要介紹了Go的interface{}底層原理實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06

最新評論

岳西县| 恩平市| 抚顺市| 安平县| 蒙自县| 二连浩特市| 广昌县| 天水市| 柏乡县| 阿拉善右旗| 荆州市| 安多县| 兰坪| 临漳县| 白山市| 平度市| 阳朔县| 缙云县| 洪泽县| 望都县| 久治县| 广昌县| 马公市| 汕尾市| 苍南县| 林芝县| 宜兴市| 翁牛特旗| 石阡县| 邢台市| 栾川县| 榆林市| 辽宁省| 新乡县| 梓潼县| 金平| 肥西县| 新密市| 旬阳县| 平谷区| 清水河县|