日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
Go語(yǔ)言為什么不支持并發(fā)讀寫(xiě)map?

01 、介紹

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

成都創(chuàng)新互聯(lián)公司公司2013年成立,先為壽光等服務(wù)建站,壽光等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢(xún)服務(wù)。為壽光企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。

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

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

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

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

02 、并發(fā)讀寫(xiě) map

Go 支持并發(fā)讀 map,不支持并發(fā)讀寫(xiě) 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ā)讀寫(xiě) map 類(lèi)型的變量 m,在運(yùn)行時(shí),返回致命錯(cuò)誤 fatal error: concurrent map read and map write。

Go 語(yǔ)言中的 map 在運(yùn)行時(shí)是怎么檢測(cè)到 map 的存在寫(xiě)操作?

源碼:

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,該字段用于標(biāo)記 map 是否為寫(xiě)入狀態(tài)。

在訪(fǎng)問(wèn) map 時(shí),通過(guò)判斷 hmap.flags 和 hashWriting 的值,可知是否有其它 goroutine 訪(fǎng)問(wèn) map,如果有,則返回致命錯(cuò)誤 fatal("concurrent map writes")。

03 、總結(jié)

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

通過(guò)閱讀源碼,我們了解到在運(yùn)行時(shí)檢測(cè)是否存在其它 goroutine 對(duì) map 的寫(xiě)操作,如果存在,則返回致命錯(cuò)誤。

讀者朋友們?cè)谑褂?nbsp;map 時(shí),要特別注意是否存在對(duì) map 的并發(fā)寫(xiě)操作,如果存在,要結(jié)合 sync 包的互斥鎖一起使用。


文章標(biāo)題:Go語(yǔ)言為什么不支持并發(fā)讀寫(xiě)map?
分享鏈接:http://www.dlmjj.cn/article/dhdscpj.html