golang:线程安全的map----sync.Map
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相关推荐
- 【Golang 源码】sync.Map 源码详解
sync.Map 不安全的 map go 中原生的 map 不是并发安全的,多个 goroutine 并发地去操作一个 map 会抛出一个 panic package main import &quo ...
- golang sync.Map和map+mutex性能比较
目录 测试环境 测试代码 运行指令 测试结果 结论 测试环境 goos: linux goarch: amd64 go version go1.14 linux/amd64 Run on (8 X 2 ...
- map与sync.Map
文章目录 map基本操作 声明及初始化 增删改查 并发场景下的map sync.Map 基本使用 sync.Map使用场景 map基本操作 声明及初始化 var m map[string]string ...
- 『每周译Go』Go sync map 的内部实现
目录 引言 a. 简单介绍并发性及其在此上下文中的应用 sync.RWMutex 和 map 一起使用的问题 介绍 sync.Map a. 在哪些场景使用 sync.Map? sync.Map 实现细 ...
- Go 学习笔记(67)— Go 并发安全字典 sync.Map
1. 并发不安全的 map Go 语言中的 map 在并发情况下,只读是线程安全的,同时读写是线程不安全的. 换句话说,在同一时间段内,让不同 goroutine 中的代码,对同一个字典进行读写操作是 ...
- sync.Map详解
导航 Golang sync.Map 详解 简单的介绍一下 Golang Map Map 使用 sync.Map sync.Map 是什么 sync.Map 使用 sync.Map 剖析 sync.m ...
- golang sync.map
在golang中,线程安全的map实现为sync.Map,相较于java中线程安全的map ConcurrentHashMap,在设计与实现上都有巨大的差别. java中的ConcurrentHash ...
- Golang sync.Map 简介与用法
Golang 中的 map 在并发情况下,只读是线程安全的,并发读写线程不安全.为了解决这个问题,Golang 提供了语言层级的并发读写安全的 sync.Map. type Map struct {/ ...
- 记一次golang中sync.Map并发创建、读取的问题
记一次golang中sync.Map并发创建.读取的问题 cunfate https://www.jianshu.com/p/f472e79909bc 背景: 我们有一个用go做的项目,其中用到了z ...
- Golang sync.Map 原理(两个map实现 读写分离、适用读多写少场景)
参考: 由浅入深聊聊Golang的sync.Map 通过对源码的逐行分析,清晰易懂 Golang sync.Map原理 通过向 sync.Map 中增删改查来介绍sync.Map的底层原理 Golan ...
最新文章
- 28岁硕士女程序员想分手!对象专科学历,北京土著,失业3个月找不到工作!遭网友群嘲!...
- ssh开发实战之整合篇
- 计算机网络核心知识(中)
- VS2005 快捷键
- AS3 CookBook学习整理(八)
- mysql的传播特性_spring事务传播特性和mysql事务隔离级别
- 拉取远程分支_git clone切换分支步骤,代理设置,作者信息设置
- CV Code|计算机视觉开源周报20200503期
- 收藏贴 :2019年必备43种区块链开发工具
- 【Java】HashMap 和 Hashtable 的 6 个区别
- wxpython 优秀的界面剂_珠海界面剂
- mpvue 中使用 iconfont
- Python爬取当当网图书数据
- 安卓对讲机安装滔滔对讲黑屏起麦黑屏对讲设置
- [UE4]Expandable Area可展开的区域
- lol无限火力服务器卡顿,LOL无限火力无限彗星BUG是什么? 无限彗星超强卡BUG技巧Get起来...
- 装备制造业ERP软件如何帮助企业做好物料齐套管理?
- android5.0+电视,当Android 5.0搭载在电视上,是一种怎样的体验?
- gis空间校正没反应_使用ArcGIS进行空间校正的步骤(矢量数据)
- 腾讯投的柠萌影视上市破发:公司市值97亿港元 曾创作《三十而已》