前言

数据竞争是并发情况下,存在多线程/协程读写相同数据的情况,必须存在至少一方写。另外,全是读的情况下是不存在数据竞争的。

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

如果map由多协程同时读和写就会出现 fatal error:concurrent map read and map write的错误。这是因为map在Go语言并发编程中,如果仅用于读取数据时候是安全的,但是在读写操作的时候是不安全的,在Go语言1.9版本后提供了一种并发安全的,sync.Map是Go语言提供的内置map,不同于基本的map数据类型,所以不能像操作基本map那样的方式操作数据,他提供了特有的方法,不需要初始化操作实现增删改查的操作。

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

sync.Map 特性

无须初始化,直接声明即可。

sync.Map 不能使用 map 的方式进行取值和设置等操作,而是使用 sync.Map 的方法进行调用,Store 表示存储,Load 表示获取,Delete 表示删除。

使用 Range 配合一个回调函数进行遍历操作,通过回调函数返回内部遍历出来的值,Range 参数中回调函数的返回值在需要继续迭代遍历时,返回 true,终止迭代遍历时,返回 false。

sync.Map提供的常用方法有如下七个:

  • Load(key interface{}) (value interface{},ok bool):通过参数key查询对应的value,如果不存在则返回nil;ok表示是否找到对应的值。
  • Store(key,value interface{}):该方法相当于对sync.Map的更新或新增,参数是键值对。
  • LoadOrStore(key,value interface{}) (actual interface{},loaded bool):该方法的参数为key和value。该方法会先根据参数key查找对应的value,如果找到则不修改原来的值并通过actual返回,并且loaded为true;如果通过key无法查找到对应的value,则存储key-value并且将存储的value通过actual返回,loaded为false。
  • Delete(key interface{}):通过key删除键值对。
  • LoadAndDelete(key interface{}):通过key删除键的值,如果有,则返回上一个值。
  • Range(f func(key,value interface{}) bool):遍历sync.Map的元素,注意for...range map是对内置map类型的用法,sync.Map需要使用单独的Range方法。

并发安全的 sync.Map 演示代码如下:

package main

import (
"fmt"
"sync"
) //声明sync.Map
var syncmap sync.Map func main() { //Store方法将键值对保存到sync.Map
syncmap.Store("zhangsan", 97)
syncmap.Store("lisi", 100)
syncmap.Store("wangmazi", 200) // LoadOrStore key不存在
v, ok := syncmap.LoadOrStore(3, "three")
fmt.Println(v, ok) // three false
// LoadOrStore key存在
v, ok = syncmap.LoadOrStore(1, "thisOne")
fmt.Println(v, ok) // one ture // Load方法获取sync.Map 键所对应的值
fmt.Println(syncmap.Load("lisi")) // Delete方法键删除对应的键值对
syncmap.Delete("lisi") var syncmap sync.Map
// LoadAndDelete key不存在
v, ok := syncmap.LoadAndDelete("xiaomi")
fmt.Println(v, ok) // <nil> false
syncmap.Store("xiaomi", "xiaomi")
// LoadAndDelete key存在
v, ok = syncmap.LoadAndDelete("xiaomi")
fmt.Println(v, ok) // xiaomi true // Range遍历所有sync.Map中的键值对
syncmap.Range(func(k, v interface{}) bool {
fmt.Println(k, v)
return true
}) }

注意

声明 score,类型为 sync.Map,注意,sync.Map 不能使用 make 创建。

将一系列键值对保存到 sync.Map 中,sync.Map 将键和值以 interface{} 类型进行保存。

Range() 方法可以遍历 sync.Map,遍历需要提供一个匿名函数,参数为 k、v,类型为 interface{},每次 Range() 在遍历一个元素时,都会调用这个匿名函数把结果返回。

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

go sync.map的使用的更多相关文章

  1. Go 1.9 sync.Map揭秘

    Go 1.9 sync.Map揭秘 目录 [−] 有并发问题的map Go 1.9之前的解决方案 sync.Map Load Store Delete Range sync.Map的性能 其它 在Go ...

  2. Golang:sync.Map

    由于map在gorountine 上不是安全的,所以在大量并发读写的时候,会出现错误. 在1.9版的时候golang推出了sync.Map. sync.Map 通过阅读源码我们发现sync.Map是通 ...

  3. go的sync.Map

    sync.Map这个数据结构是线程安全的(基本类型Map结构体在并发读写时会panic严重错误),它填补了Map线程不安全的缺陷,不过最好只在需要的情况下使用.它一般用于并发模型中对同一类map结构体 ...

  4. sync.Map(在并发环境中使用的map)

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

  5. sync.Map与Concurrent Map

    1. sync.Map 1.1. map并发不安全 go1.6以后map有了并发的安全检查,所以如果在并发环境中读写map就会报错 func unsafeMap() { // 创建一个map对象 m ...

  6. golang 标准库 sync.Map 中 nil 和 expunge 区别

    本文不是 sync.Map 源码详细解读,而是聚焦 entry 的不同状态,特别是 nil 状态和 expunge 状态的区分. entry 是 sync.Map 存放值的结构体,其值有三种,分别为 ...

  7. 图解Go里面的sync.Map了解编程语言核心实现源码

    基础筑基 在大多数语言中原始map都不是一个线程安全的数据结构,那如果要在多个线程或者goroutine中对线程进行更改就需要加锁,除了加1个大锁,不同的语言还有不同的优化方式, 像在java和go这 ...

  8. 源码解读 Golang 的 sync.Map 实现原理

    简介 Go 的内建 map 是不支持并发写操作的,原因是 map 写操作不是并发安全的,当你尝试多个 Goroutine 操作同一个 map,会产生报错:fatal error: concurrent ...

  9. 深度解密 Go 语言之 sync.map

    工作中,经常会碰到并发读写 map 而造成 panic 的情况,为什么在并发读写的时候,会 panic 呢?因为在并发读写的情况下,map 里的数据会被写乱,之后就是 Garbage in, garb ...

  10. 深入理解golang:sync.map

    疑惑开篇 有了map为什么还要搞个sync.map 呢?它们之间有什么区别? 答:重要的一点是,map并发不是安全的. 在Go 1.6之前, 内置的map类型是部分goroutine安全的,并发的读没 ...

随机推荐

  1. SSM或Spring Boot开发中,mapper包中的mapper.xml没有编译到targger中的解决办法

    SSM或Spring Boot开发中,mapper包中的mapper.xml没有编译到targger中的解决办法 在pom文件中加入如下配置: <resources> <!-- 编译 ...

  2. 长连接网关技术专题(十一):揭秘腾讯公网TGW网关系统的技术架构演进

    本文由腾讯技术团队peter分享,原题"腾讯网关TGW架构演进之路",下文进行了排版和内容优化等. 1.引言 TGW全称Tencent Gateway,是一套实现多网统一接入,支持 ...

  3. 【译】GitHub Copilot Free 在 Visual Studio 中

    可能您还没有听说过,GitHub 刚刚宣布了 Copilot Free(免费版)!好消息是:您现在已经可以在 Visual Studio 中开始使用 Copilot Free 了.它现在已经可用了,我 ...

  4. Diary -「联合省选 2023」鸢尾

    零   她们诞生于那样一段迷茫的时期,她们总是一个唱着虚幻的梦呓,一个哼着现实的词曲.   「平行的世界 / 另一个 / 我是怎样的」?如果那时的,虚幻的歌者没有妥协,现在的她会是怎样的人呢?   我 ...

  5. MyBatis的深入原理-架构设计以及实例分析

    MyBatis是目前非常流行的ORM框架,它的功能很强大,然而其实现却比较简单.优雅.本文主要讲述MyBatis的架构设计思路,并且讨论MyBatis的几个核心部件,然后结合一个select查询实例, ...

  6. colab 使用技巧

    无法进入目录 import os path = "/content/TaBERT/" os.chdir(path) print(os.getcwd()) 无法执行conda !pi ...

  7. fopen在VS中不安全的问题

    问题 fopen函数哎VS中使用,报错: error C4996: 'fopen': This function or variable may be unsafe. Consider using f ...

  8. 硬件设计:电路防护--TVS管

    参考资料:TVS参数及选型方法 TVS参数理解 深圳市硕凯电子有限公司元器件产品说明 TVS(Transient Voltage suppressor)或称瞬变电压抑制二极管.当TVS管两端经受瞬间的 ...

  9. 我喜欢 amy 同学的腿……

    1.我是人间之屑,这点我先承认大约不会错,但并不代表我的一切都是 hitonokuzu 为了防止对成语的吴勇(迫真),这就是人渣的意思. 2.看来亚里士多德的观点还是没有过时,老祖宗说的对.老祖宗指的 ...

  10. [源码分析] Facebook如何训练超大模型--- (5)

    [源码分析] Facebook如何训练超大模型--- (5) 目录 [源码分析] Facebook如何训练超大模型--- (5) 0x00 摘要 0x01 背景 0x02 思路 2.1 学习建议 2. ...