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

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

 更新時(shí)間:2022年12月15日 09:50:08   作者:小馬別過(guò)河  
這篇文章主要為大家介紹了Go Map并發(fā)沖突預(yù)防與解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

背景

關(guān)于 Go 語(yǔ)言的 Map,有兩個(gè)需要注意的特性:

  • Map 是并發(fā)讀寫(xiě)不安全的,這是出于性能的考慮;
  • Map 并發(fā)讀寫(xiě)導(dǎo)致的錯(cuò)誤,無(wú)法使用 recover 捕獲。

后者意味著,只有出現(xiàn)并發(fā)讀寫(xiě)的問(wèn)題,服務(wù)就會(huì)掛掉。

這兩個(gè)特性可能大家都知道,可即使有這個(gè)共識(shí),我還是見(jiàn)過(guò)這個(gè)問(wèn)題導(dǎo)致的事故。

事故的大致情況是,一個(gè)人封裝了map的讀寫(xiě),沒(méi)有使用鎖。另一個(gè)人開(kāi)協(xié)程讀寫(xiě) map。而測(cè)試環(huán)境請(qǐng)求量小,不一定會(huì)導(dǎo)致崩潰,于是,這個(gè)問(wèn)題就留到生產(chǎn)環(huán)境才出現(xiàn)了。

除了靠開(kāi)發(fā)者自覺(jué)和 code review,還能怎么預(yù)防這種情況呢?我覺(jué)得在單元測(cè)試加入并行測(cè)試也很重要。

并行單元測(cè)試

單元測(cè)試默認(rèn)不是并發(fā)的,比如下面的單測(cè),是可以通過(guò)的:

func TestConcurrent(t *testing.T) {
    var m = map[string]int{}
    // 寫(xiě) map
    t.Run("write", func(t *testing.T) {
      for i := 0; i < 10000; i++ {
        m["a"] = 1
      }
    })
    // 讀 map
    t.Run("read", func(t *testing.T) {
      for i := 0; i < 10000; i++ {
        _ = m["a"]
      }
    })
}

但是我們的期望是,上面的單測(cè)不通過(guò),該如何解決呢?

testing.T 有一個(gè) Parallel 方法,它表示當(dāng)前測(cè)試會(huì)和其他測(cè)試并行運(yùn)行。 如果參數(shù)有-test.count-test.cpu,一個(gè)測(cè)試可能運(yùn)行多次,同個(gè)測(cè)試的多個(gè)運(yùn)行實(shí)例,不會(huì)并行運(yùn)行。

我們給上面的單測(cè),加上t.Parallel():

func TestConcurrent(t *testing.T) {
    var m = map[string]int{}
    t.Run("write", func(t *testing.T) {
      // 加上并行
      t.Parallel()
      for i := 0; i < 10000; i++ {
        m["a"] = 1
      }
    })
    t.Run("read", func(t *testing.T) {
      // 加上并行
      t.Parallel()
      for i := 0; i < 10000; i++ {
        _ = m["a"]
      }
    })
}

這次執(zhí)行就會(huì)報(bào)錯(cuò):

fatal error: concurrent map read and map write

支持并發(fā)的 Map

讓 Map 支持并發(fā)讀寫(xiě)并不麻煩,常見(jiàn)的做法有:

  • 操作 map 的時(shí)候,加上讀寫(xiě)鎖 sync.RWMutex;
  • 使用 sync.Map。

sync.RWMutex 大家用得可能比較多。這里簡(jiǎn)單給個(gè)demo。

sync.RWMutex

我們給上面的單測(cè)加上鎖,這次運(yùn)行就能通過(guò)了。

func TestConcurrent(t *testing.T) {
	var m = map[string]int{}
	//  定義鎖,零值就可以使用
	var mu sync.RWMutex
	t.Run("write", func(t *testing.T) {
		t.Parallel()
		for i := 0; i < 10000; i++ {
			// 鎖
			mu.Lock()
			m["a"] = 1
			// 解鎖
			mu.Unlock()
		}
	})
	t.Run("read", func(t *testing.T) {
		t.Parallel()
		for i := 0; i < 10000; i++ {
			// 鎖
			mu.Lock()
			_ = m["a"]
			// 解鎖
			mu.Unlock()
		}
	})
}

本文的重點(diǎn)介紹一下Go標(biāo)準(zhǔn)庫(kù)自帶的,支持并發(fā)讀寫(xiě)的 map:sync.Map

sync.Map

sync.Map 就是線(xiàn)程安全版的 map[interface{}]interface{},零值可以直接使用,值不能復(fù)制。它主要用于以下場(chǎng)景:

  • 當(dāng)同一個(gè) key 的值,寫(xiě)少讀多的時(shí)候;
  • 但多個(gè) goroutines 讀寫(xiě)或修改一系列不同的key的時(shí)候。

上面兩種場(chǎng)景中,比起帶Mutex(或RWMutex)的map,sync.Map 會(huì)大大減少鎖的競(jìng)爭(zhēng)。

sync.Map 提供的方法不多,這里列出一些。注意的是,any 是 go 1.18 中 interface{}的別名。

Store,設(shè)置 key-value。

func (m *Map) Store(key, value any)

Load, 根據(jù) key 讀取 value。

func (m *Map) Load(key any) (value any, ok bool)

Delete,刪除某個(gè)key。

func (m *Map) Delete(key any)

Range,遍歷所有key, 如果f返回false,會(huì)停止遍歷。

func (m *Map) Range(f func(key, value any) bool)

還有 LoadAndDelete(讀后刪除)、LoadOrStore(讀key,不存在時(shí)設(shè)置)。

我們給上面的單測(cè),使用sync.Map,測(cè)試也可以通過(guò)。

func TestConcurrent(t *testing.T) {
	// 可以使用零值
	var m sync.Map
	t.Run("write", func(t *testing.T) {
		t.Parallel()
		for i := 0; i < 10000; i++ {
			// 寫(xiě)
			m.Store("a", 1)
		}
	})
	t.Run("read", func(t *testing.T) {
		t.Parallel()
		for i := 0; i < 10000; i++ {
			// 讀
			v, ok := m.Load("a")
			if ok {
				_ = v.(int)
			}
		}
	})
}

參考

pkg.go.dev/sync#Map

以上就是Go Map并發(fā)沖突預(yù)防與解決的詳細(xì)內(nèi)容,更多關(guān)于Go Map并發(fā)沖突的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go基礎(chǔ)教程系列之回調(diào)函數(shù)和閉包詳解

    Go基礎(chǔ)教程系列之回調(diào)函數(shù)和閉包詳解

    這篇文章主要介紹了Go基礎(chǔ)教程系列之回調(diào)函數(shù)和閉包詳解,需要的朋友可以參考下
    2022-04-04
  • go引入自建包名報(bào)錯(cuò):package?XXX?is?not?in?std解決辦法

    go引入自建包名報(bào)錯(cuò):package?XXX?is?not?in?std解決辦法

    這篇文章主要給大家介紹了go引入自建包名報(bào)錯(cuò):package?XXX?is?not?in?std的解決辦法,這是在寫(xiě)測(cè)試引入包名的時(shí)候遇到的錯(cuò)誤提示,文中將解決辦法介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • golang?cache帶索引超時(shí)緩存庫(kù)實(shí)戰(zhàn)示例

    golang?cache帶索引超時(shí)緩存庫(kù)實(shí)戰(zhàn)示例

    這篇文章主要為大家介紹了golang?cache帶索引超時(shí)緩存庫(kù)實(shí)戰(zhàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • golang os.Eixt使用示例

    golang os.Eixt使用示例

    在Go語(yǔ)言中,os.Exit函數(shù)用于立即終止程序并返回一個(gè)指定的退出狀態(tài)碼,本文就來(lái)介紹一下golang os.Eixt使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-10-10
  • golang API請(qǐng)求隊(duì)列的實(shí)現(xiàn)

    golang API請(qǐng)求隊(duì)列的實(shí)現(xiàn)

    本文主要介紹了golang API請(qǐng)求隊(duì)列的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • 詳解go語(yǔ)言中sort如何排序

    詳解go語(yǔ)言中sort如何排序

    我們的代碼業(yè)務(wù)中很多地方需要我們自己進(jìn)行排序操作,本文主要介紹了詳解go語(yǔ)言中sort如何排序,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • 詳解如何在Golang中實(shí)現(xiàn)HMAC

    詳解如何在Golang中實(shí)現(xiàn)HMAC

    HMAC(Hash-based Message Authentication Code)是一種基于 Hash 函數(shù)和密鑰的消息認(rèn)證碼,HMAC將密鑰、消息和哈希函數(shù)一起使用,確保消息在傳輸過(guò)程中不被篡改,還可以驗(yàn)證消息的發(fā)送者身份,本文詳細(xì)講解了如何在Golang中實(shí)現(xiàn)HMAC,需要的朋友可以參考下
    2023-11-11
  • go語(yǔ)言檢測(cè)文件是否存在的方法

    go語(yǔ)言檢測(cè)文件是否存在的方法

    這篇文章主要介紹了go語(yǔ)言檢測(cè)文件是否存在的方法,實(shí)例分析了Go語(yǔ)言文件操作的相關(guān)技巧,需要的朋友可以參考下
    2015-03-03
  • Go語(yǔ)言常見(jiàn)錯(cuò)誤之將接口定義在實(shí)現(xiàn)方

    Go語(yǔ)言常見(jiàn)錯(cuò)誤之將接口定義在實(shí)現(xiàn)方

    在Go中,接口起到一個(gè)十分關(guān)鍵的角色,它們提供了一種方式來(lái)定義對(duì)象的行為,而不需要知道對(duì)象的具體實(shí)現(xiàn),一個(gè)常見(jiàn)的錯(cuò)誤是在實(shí)現(xiàn)方而不是使用方定義接口,本文將詳細(xì)探討為何這樣做是一個(gè)錯(cuò)誤,以及如何避免它
    2024-01-01
  • GO的range具體使用

    GO的range具體使用

    GO語(yǔ)言的for…range 能做什么呢?golang的for…range是go 身的語(yǔ)法,可以用來(lái)遍歷數(shù)據(jù)結(jié)構(gòu),本文就詳細(xì)的來(lái)介紹一下具體使用,感興趣的可以了解一下
    2021-10-10

最新評(píng)論

子洲县| 龙山县| 安平县| 建德市| 成安县| 子洲县| 木兰县| 达日县| 长沙市| 仁化县| 嵊州市| 革吉县| 苍山县| 台北县| 沈丘县| 广平县| 岢岚县| 仪陇县| 高碑店市| 武城县| 竹溪县| 渝中区| 乌兰察布市| 平凉市| 柳林县| 屏南县| 湘潭县| 元阳县| 房产| 长丰县| 武宣县| 扶风县| 巴里| 宜阳县| 长寿区| 樟树市| 山阴县| 曲周县| 合江县| 湘潭县| 五台县|