日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

Go 语言为什么不支持并发读写 map?

發布時間:2024/1/16 windows 40 coder
生活随笔 收集整理的這篇文章主要介紹了 Go 语言为什么不支持并发读写 map? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

大家好,我是 frank ,「 Golang 語言開發棧」公眾號作者。

01 介紹

在 Go 語言項目開發中,我們經常會使用哈希表 map,它的時間復雜度是 O(1),Go 語言中的 map 使用開放尋址法避免哈希碰撞。

Go 語言中的 map 并非原子操作,不支持并發讀寫操作。

Go 官方認為 map 在大多數情況下是使用 map 進行并發讀操作,僅在少數情況下是使用 map 進行并發讀寫操作。

如果 Go 語言中的 map 原生支持并發讀寫操作,在操作時需要先獲取互斥鎖,反而會降低只有并發讀操作時的性能。

在需要并發讀寫操作 map 時,可以結合 sync 包中的互斥鎖一起使用。

02 并發讀寫 map

Go 支持并發讀 map,不支持并發讀寫 map

示例代碼:

func main() {
	var m = make(map[int]string)

	go func() {
		for {
			m[1] = "xx"
		}
	}()

	go func() {
		for {
			_ = m[1]
		}
	}()
	time.Sleep(time.Second * 3)
}

輸出結果:

fatal error: concurrent map read and map write
// ...

閱讀上面這段代碼,我們并發讀寫 map 類型的變量 m,在運行時,返回致命錯誤 fatal error: concurrent map read and map write

Go 語言中的 map 在運行時是怎么檢測到 map 的存在寫操作?

源碼:

const (
	// flags
	iterator     = 1 // there may be an iterator using buckets
	oldIterator  = 2 // there may be an iterator using oldbuckets
	hashWriting  = 4 // a goroutine is writing to the map
	sameSizeGrow = 8 // the current map growth is to a new map of the same size
)
// A header for a Go map.
type hmap struct {
	count     int // # live cells == size of map.  Must be first (used by len() builtin)
	flags     uint8
	B         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
	noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
	hash0     uint32 // hash seed

	buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
	oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
	nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)

	extra *mapextra // optional fields
}

// Like mapaccess, but allocates a slot for the key if it is not present in the map.
func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
	// ...

done:
	if h.flags&hashWriting == 0 {
		fatal("concurrent map writes")
	}
	h.flags &^= hashWriting
	if t.IndirectElem() {
		elem = *((*unsafe.Pointer)(elem))
	}
	return elem
}

閱讀上面這段源碼,我們可以發現在 hmap 結構體中的字段 flags,該字段用于標記 map 是否為寫入狀態。

在訪問 map 時,通過判斷 hmap.flagshashWriting 的值,可知是否有其它 goroutine 訪問 map,如果有,則返回致命錯誤 fatal("concurrent map writes")

03 總結

本文介紹 Go 語言為什么不支持并發讀寫 map,Go 官方的說法是在多數情況下 map 只存在并發讀操作,如果原生支持并發讀寫,即降低了并發讀操作的性能。

通過閱讀源碼,我們了解到在運行時檢測是否存在對 map 的寫操作,如果存在,則返回致命錯誤。

讀者朋友們在使用 map 時,要特別注意是否存在對 map 的并發寫操作,如果存在,要結合 sync 包的互斥鎖一起使用。

總結

以上是生活随笔為你收集整理的Go 语言为什么不支持并发读写 map?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。