map

线程不安全

Go语言中的 map 在并发情况下,只读是线程安全的,同时读写是线程不安全的。

下面来看下并发情况下读写 map 时会出现的问题,代码如下:

package mainimport "fmt"func main() {m := make(map[int]int)go func() {// 不停地对map进行写入for  {m[1] = 1}}()go func() {// 不停地对map进行读取for {_ = m[1]}}()fmt.Scanln()
}

无法运行,报错:

fatal error: concurrent map read and map write

错误信息显示:并发的map读和map写,也就是说使用了两个并发函数不断的对map进行读和写而发生了竞态问题,map 内部会对这种并发操作进行检查并提前发现。

需要并发读写时,一般的做法是加锁,但这样性能并不高,Go语言在 1.9 版本中提供了一种效率较高的并发安全的 sync.Map,sync.Map 和 map 不同,不是以语言原生形态提供,而是在 sync 包下的特殊结构。

解决方法

加锁

package mainimport ("fmt""sync""time"
)type SyncMap struct {mymap map[string]string//读写锁包含一对相关的锁,读锁用于只读操作,写锁用于写操作。读锁可能由多个读线程同时运行,写锁是唯一的。// * 读锁和写锁之间是互斥的,同一时间只能有一个在运行。但是可以有多个线程同时读取数据。// * 写入数据之前必须重新确认(ReCheck)状态,因为其他的线程可能会拿到写锁再一次修改我们已经修改过的值。这是因为前一个线程拿到写锁之后,后面的线程会被阻塞。当前一个线程释放写锁之后,被阻塞的线程会继续运行完成被阻塞的部分代码,所以才会出现这样的情况。// * 当某一个线程上了写锁之后,自己仍然可以上读锁,之后在释放写锁,这是一种降级(Downgrade)的处理方法。*sync.RWMutex //读写锁
}
var smap SyncMap //公有的访问map
var done  chan  bool//通道,是否完成
func main() {smap = SyncMap{map[string]string{}, new(sync.RWMutex)}done = make(chan bool, 1000)go func() {for   {smap.Lock()smap.mymap["1"] = "1";smap.Unlock()done<-truetime.Sleep(1*time.Millisecond)}}()go func() {for   {smap.Lock()smap.mymap["1"] = "2";smap.Unlock()done<-truetime.Sleep(1*time.Millisecond)}}()var lastlength = 0var lock sync.Mutexgo func() {for   {if len(done) != lastlength {lock.Lock()lastlength = len(done)lock.Unlock()smap.RLock()fmt.Print(smap.mymap["1"] , "\t")if len(done) % 5 ==0{fmt.Println("  " , lastlength)}smap.RUnlock()}}}()for {if len(done)==1000{fmt.Println("通道已经满了")break}else{time.Sleep(1*time.Second) }}
}

sync.Map

type Map struct
func (m *Map) Store(key, value interface{})
func (m *Map) Load(key interface{}) (value interface{}, ok bool)
func (m *Map) Range(f func(key, value interface{}) bool)
func (m *Map) Delete(key interface{})

sync.Map 有以下特性:

  • 无须初始化,直接声明即可。
  • sync.Map 不能使用 map 的方式进行取值和设置等操作,而是使用 sync.Map 的方法进行调用,Store 表示存储,Load 表示获取,Delete 表示删除。
  • 使用 Range 配合一个回调函数进行遍历操作,通过回调函数返回内部遍历出来的值,Range 参数中回调函数的返回值在需要继续迭代遍历时,返回 true,终止迭代遍历时,返回 false。
  • LoadOrStore:参数是一对key:value,如果该key存在且没有被标记删除则返回原先的value(不更新)和true;不存在则store,返回该value 和false
package mainimport ("fmt""sync"
)func main() {var m sync.Mapm.Store("bb", 22)m.Store("cc", 33)m.Store("aa", 11)m.Store("dd", 33)m.Store("ee", 11)//Load 方法,获得valueif v, ok := m.Load("cc");ok{fmt.Printf("Load 方法,获得value   %v: %v\n", v, ok)}m.Delete("cc")//LoadOrStore方法,获取或者保存// 就是如果key还在,那么就保持原来并返回原来的值,如果key不存在就存储if vv,ok:=m.LoadOrStore("bb", 22);ok{fmt.Println(vv)}else{fmt.Printf("LoadOrStore 方法,获得value   %v: %v\n", vv, ok)}//遍历该mapm.Range(func(key, value interface{}) bool {fmt.Printf("[%v]=[%v]\n", key, value)return true})
}

sync.Map 没有提供获取 map 数量的方法,替代方法是在获取 sync.Map 时遍历自行计算数量,sync.Map 为了保证并发安全有一些性能损失,因此在非并发情况下,使用 map 相比使用 sync.Map 会有更好的性能。

golang:线程安全的map----sync.Map相关推荐

  1. 【Golang 源码】sync.Map 源码详解

    sync.Map 不安全的 map go 中原生的 map 不是并发安全的,多个 goroutine 并发地去操作一个 map 会抛出一个 panic package main import &quo ...

  2. golang sync.Map和map+mutex性能比较

    目录 测试环境 测试代码 运行指令 测试结果 结论 测试环境 goos: linux goarch: amd64 go version go1.14 linux/amd64 Run on (8 X 2 ...

  3. map与sync.Map

    文章目录 map基本操作 声明及初始化 增删改查 并发场景下的map sync.Map 基本使用 sync.Map使用场景 map基本操作 声明及初始化 var m map[string]string ...

  4. 『每周译Go』Go sync map 的内部实现

    目录 引言 a. 简单介绍并发性及其在此上下文中的应用 sync.RWMutex 和 map 一起使用的问题 介绍 sync.Map a. 在哪些场景使用 sync.Map? sync.Map 实现细 ...

  5. Go 学习笔记(67)— Go 并发安全字典 sync.Map

    1. 并发不安全的 map Go 语言中的 map 在并发情况下,只读是线程安全的,同时读写是线程不安全的. 换句话说,在同一时间段内,让不同 goroutine 中的代码,对同一个字典进行读写操作是 ...

  6. sync.Map详解

    导航 Golang sync.Map 详解 简单的介绍一下 Golang Map Map 使用 sync.Map sync.Map 是什么 sync.Map 使用 sync.Map 剖析 sync.m ...

  7. golang sync.map

    在golang中,线程安全的map实现为sync.Map,相较于java中线程安全的map ConcurrentHashMap,在设计与实现上都有巨大的差别. java中的ConcurrentHash ...

  8. Golang sync.Map 简介与用法

    Golang 中的 map 在并发情况下,只读是线程安全的,并发读写线程不安全.为了解决这个问题,Golang 提供了语言层级的并发读写安全的 sync.Map. type Map struct {/ ...

  9. 记一次golang中sync.Map并发创建、读取的问题

    记一次golang中sync.Map并发创建.读取的问题  cunfate https://www.jianshu.com/p/f472e79909bc 背景: 我们有一个用go做的项目,其中用到了z ...

  10. Golang sync.Map 原理(两个map实现 读写分离、适用读多写少场景)

    参考: 由浅入深聊聊Golang的sync.Map 通过对源码的逐行分析,清晰易懂 Golang sync.Map原理 通过向 sync.Map 中增删改查来介绍sync.Map的底层原理 Golan ...

最新文章

  1. 28岁硕士女程序员想分手!对象专科学历,北京土著,失业3个月找不到工作!遭网友群嘲!...
  2. ssh开发实战之整合篇
  3. 计算机网络核心知识(中)
  4. VS2005 快捷键
  5. AS3 CookBook学习整理(八)
  6. mysql的传播特性_spring事务传播特性和mysql事务隔离级别
  7. 拉取远程分支_git clone切换分支步骤,代理设置,作者信息设置
  8. CV Code|计算机视觉开源周报20200503期
  9. 收藏贴 :2019年必备43种区块链开发工具
  10. 【Java】HashMap 和 Hashtable 的 6 个区别
  11. wxpython 优秀的界面剂_珠海界面剂
  12. mpvue 中使用 iconfont
  13. Python爬取当当网图书数据
  14. 安卓对讲机安装滔滔对讲黑屏起麦黑屏对讲设置
  15. [UE4]Expandable Area可展开的区域
  16. lol无限火力服务器卡顿,LOL无限火力无限彗星BUG是什么? 无限彗星超强卡BUG技巧Get起来...
  17. 装备制造业ERP软件如何帮助企业做好物料齐套管理?
  18. android5.0+电视,当Android 5.0搭载在电视上,是一种怎样的体验?
  19. gis空间校正没反应_使用ArcGIS进行空间校正的步骤(矢量数据)
  20. 腾讯投的柠萌影视上市破发:公司市值97亿港元 曾创作《三十而已》

热门文章

  1. Lamento剧情(巴鲁多X柯诺尔)
  2. Surfer13 自动实现网格化
  3. python txt默认读取字符还是行,python读取中文txt文本的方法
  4. 各地级市GDP及第一二三产业GDP数据(1999-2019年)
  5. VUE安装成功无法创建项目
  6. 从 left-pad 事件我们可以学到什么
  7. 转---找女朋友的标准
  8. iPhone忘记密码怎么解锁
  9. python中int的功能_Python内置函数int()高级用法
  10. 总结了10句话,送给所有的通信新员工