自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Go 語言為什么不支持并發(fā)讀寫 map?

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

01 、介紹

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

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

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

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

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

02 、并發(fā)讀寫 map

Go 支持并發(fā)讀 map,不支持并發(fā)讀寫 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)
}

輸出結(jié)果:

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

閱讀上面這段代碼,我們并發(fā)讀寫 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
}

閱讀上面這段源碼,我們可以發(fā)現(xiàn)在 hmap 結(jié)構(gòu)體中的字段 flags,該字段用于標記 map 是否為寫入狀態(tài)。

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

03 、總結(jié)

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

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

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

責任編輯:武曉燕 來源: Golang語言開發(fā)棧
相關(guān)推薦

2024-01-05 08:45:35

Go語言map

2022-01-10 23:54:56

GoMap并發(fā)

2021-10-27 07:15:36

Go 循環(huán)引用

2021-12-09 10:51:47

Go繼承

2021-12-15 07:49:22

Go語言設(shè)計

2024-03-12 09:13:28

Go語言main

2023-01-28 08:05:32

轉(zhuǎn)換Go泛型

2024-05-28 08:55:52

2021-11-08 11:02:01

Go函數(shù)重載

2023-02-26 23:36:08

PHPGo函數(shù)

2020-07-22 08:01:41

Python開發(fā)運算符

2020-10-09 06:48:19

Pythonswitch語句

2024-03-08 08:51:59

Gomain函數(shù)

2009-03-12 08:42:38

AndroidWMMTK

2021-08-02 09:31:20

Python工具代碼

2021-06-11 00:03:31

鴻蒙智能手機

2021-02-01 13:53:53

StringlongJava

2023-04-03 11:21:29

PythonGoRust

2009-03-11 17:32:22

聯(lián)發(fā)科WMAndroid

2021-07-13 08:09:34

微博推特評論
點贊
收藏

51CTO技術(shù)棧公眾號