当前位置:首页 > 科技  > 软件

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

来源: 责编: 时间:2024-01-02 09:29:55 147观看
导读01 、介绍在 Go 语言项目开发中,我们经常会使用哈希表 map,它的时间复杂度是 O(1),Go 语言中的 map 使用开放寻址法避免哈希碰撞。Go 语言中的 map 并非原子操作,不支持并发读写操作。Go 官方认为 map 在大多数情况下是使

01 、介绍

在 Go 语言项目开发中,我们经常会使用哈希表 map,它的时间复杂度是 O(1),Go 语言中的 map 使用开放寻址法避免哈希碰撞。pEB28资讯网——每日最新资讯28at.com

Go 语言中的 map 并非原子操作,不支持并发读写操作。pEB28资讯网——每日最新资讯28at.com

Go 官方认为 map 在大多数情况下是使用 map 进行并发读操作,仅在少数情况下是使用 map 进行并发读写操作。pEB28资讯网——每日最新资讯28at.com

如果 Go 语言中的 map 原生支持并发读写操作,在操作时需要先获取互斥锁,反而会降低只有并发读操作时的性能。pEB28资讯网——每日最新资讯28at.com

在需要并发读写操作 map 时,可以结合 sync 包中的互斥锁一起使用。pEB28资讯网——每日最新资讯28at.com

02 、并发读写 map

Go 支持并发读 map,不支持并发读写 map。pEB28资讯网——每日最新资讯28at.com

示例代码:pEB28资讯网——每日最新资讯28at.com

func main() { var m = make(map[int]string) go func() {  for {   m[1] = "xx"  } }() go func() {  for {   _ = m[1]  } }() time.Sleep(time.Second * 3)}

输出结果:pEB28资讯网——每日最新资讯28at.com

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

阅读上面这段代码,我们并发读写 map 类型的变量 m,在运行时,返回致命错误 fatal error: concurrent map read and map write。pEB28资讯网——每日最新资讯28at.com

Go 语言中的 map 在运行时是怎么检测到 map 的存在写操作?pEB28资讯网——每日最新资讯28at.com

源码:pEB28资讯网——每日最新资讯28at.com

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 是否为写入状态。pEB28资讯网——每日最新资讯28at.com

在访问 map 时,通过判断 hmap.flags 和 hashWriting 的值,可知是否有其它 goroutine 访问 map,如果有,则返回致命错误 fatal("concurrent map writes")。pEB28资讯网——每日最新资讯28at.com

03 、总结

本文介绍 Go 语言为什么不支持并发读写 map,Go 官方的说法是在多数情况下 map 只存在并发读操作,如果原生支持并发读写,即降低了并发读操作的性能。pEB28资讯网——每日最新资讯28at.com

通过阅读源码,我们了解到在运行时检测是否存在其它 goroutine 对 map 的写操作,如果存在,则返回致命错误。pEB28资讯网——每日最新资讯28at.com

读者朋友们在使用 map 时,要特别注意是否存在对 map 的并发写操作,如果存在,要结合 sync 包的互斥锁一起使用。pEB28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-55047-0.htmlGo 语言为什么不支持并发读写 map?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 大模型应用设计与实现指南,你学会了吗?

下一篇: Kubernetes CRD & Operator 简介

标签:
  • 热门焦点
Top