golang的map是不是并发安全的?怎么保证安全?

参考链接
https://www.iamshuaidi.com/23354.html

map 并不是并发安全的

map是引用类型,如果两个map同时指向一个底层,那么一个map的变动会影响到另一个map。 map 的并发不安全主要是因为缺乏内置的锁机制和原子操作,并且在扩容过程中可能会导致数据不一致。

  • 无锁机制: map 的底层数据结构是一个哈希表,当多个 Goroutine 并发地对 map 进行读写操作时,可能会导致数据竞争(DataRace)。因为 map 没有内置的锁机制来保护并发访问,所以在并发读写时可能会造成数据不一致或损坏。

  • 非原子操作: 尽管 map 的操作看起来是单个的语句,比如 m[key] = value 和 delete(m,key),但实际上它们都不是原子操作。在并发环境中,一个 map 操作可能会由多个机器指令组成,而且在执行期间可能会被中断或切换到另一个Goroutine,这就增加了出错的可能性。

  • 扩容操作【重点】: 当 map 的元素个数超过了当前容量的时候,Go 语言会自动扩容map,这时会重新分配内存,并将原有的键值对重新哈希到新的内存位置。在扩容过程中,如果有其他 Goroutine并发地进行读写操作,可能会导致指针失效、丢失数据或者死锁等问题。

因此,这意味着在多个 Goroutine 同时读取和写入 map 时可能会导致竞态条件(Race Condition)和数据竞争(Data Race)。当多个 Goroutine 并发地读取和写入同一个 map 时,可能会出现不可预期的结果,甚至导致程序崩溃。

要保证 map 的并发安全,可以采取以下几种方式:

使用互斥锁(Mutex)
使用读写互斥锁(RWMutex)
使用并发安全的数据结构:sync.Map

1. 使用互斥锁(Mutex)

可以在读取和写入 map 的操作上加锁,保证同一时刻只有一个 Goroutine 能够访问 map。通过 sync.Mutex 提供的锁机制可以很容易地实现这一点。

import "sync"var mu sync.Mutex
var m = make(map[string]int)// 写操作
mu.Lock()
m["key"] = value
mu.Unlock()// 读操作
mu.Lock()
value := m["key"]
mu.Unlock()

2. 使用读写互斥锁(RWMutex):

如果多个 Goroutine 需要同时读取 map,但只有一个 Goroutine 写入 map,可以使用 sync.RWMutex 提供的读写锁机制。这种方式可以提高并发读取的效率。

import "sync"var mu sync.RWMutex
var m = make(map[string]int)// 写操作
mu.Lock()
m["key"] = value
mu.Unlock()// 读操作
mu.RLock()
value := m["key"]
mu.RUnlock()

3. 使用并发安全的数据结构:

在 Go 语言的 sync 包中还提供了一些并发安全的数据结构,例如 sync.Map。使用 sync.Map 可以避免手动管理锁,简化并发编程。

import "sync"var m sync.Map// 写操作
m.Store("key", value)// 读操作
value, ok := m.Load("key")

总的来说,要保证 map 的并发安全,需要在并发访问时进行适当的同步控制,使用锁机制或并发安全的数据结构来保护 map 的读写操作。

===========================
额外知识:

  1. map是引用类型,如果两个map同时指向一个底层,那么一个map的变动会影响到另一个map。
  2. map的零值(Zero Value)是nil,对nil map进行任何添加元素的操作都会触发运行时错误(panic)。因此,使用前必须先创建map,使用make函数,例如:m := make(map[string]int)。
  3. map的键可以是任何可以用 == 或!=操作符比较的类型,如字符串,整数,浮点数,复数,布尔等。但是,slice,map,和function类型不可以作为map的键,因为这些类型不能使用==或!=操作符进行比较。
  4. map在使用过程中不保证遍历顺序,即:map的遍历结果顺序可能会不一样,所以在需要顺序的场合,要自行处理数据并排序。
  5. map进行的所有操作,包括读取,写入,删除,都是不安全的。也就是说,如果你在一个goroutine中修改map,同时在另一个goroutine中读取map,可能会触发“concurrent map read and map write”的错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/702750.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux环境安装ffmpeg6.x

1.官网ffmpeg下载源码 https://ffmpeg.org/download.html#build-windows 2.未安装x264库则先安装配置 可以先查询x264库: whereis libx264 安装编译工具和依赖库: sudo yum install gcc make cmake mercurial git yasm pkgconfig autoconf automake libtool sudo…

RabbitMQ 面试八股题整理

前言:本文是博主网络自行收集的一些RabbitMQ相关八股文,还在准备暑期实习,后续应该会持续更新...... 参考:三天吃透RabbitMQ面试八股文_牛客网 目录 RabbitMQ概述 什么是 RabbitMQ? 说一说RabbitMQ中的AMQP 为什么…

zabbix监控业务数据

前言 监控系统除了监控os和数据库性能相关的指标外,业务数据也是重点监控的对象。 一线驻场的运维同学应该深有体会,每天需要向甲方或者公司反馈现场的数据情况,正常情况下一天巡检两次,早上上班后和下午下班前各一次。监控项目…

【C语言】指针初阶

正文开始之前,我们要记住一个东西就是:地址指针 目录 一、指针的解释二、指针变量和地址1、取地址操作符2、指针变量和解引用操作1、指针变量2、拆解指针类型3、解引用操作符4、注意事项 3、指针变量的大小4、指针的解引用5、void*指针 三、指针的运算1、…

数据结构:链表的冒泡排序

法一:修改指针指向 //法二 void maopao_link(link_p H){if(HNULL){printf("头节点为空\n");return;}if(link_empty(H)){printf("链表为空\n");return;}link_p tailNULL;while(H->next->next!tail){link_p pH;link_p qH->next;while(q…

mysql的隔离级别,和实现

参考链接 https://xiaolincoding.com/mysql/transaction/mvcc.html#%E4%BA%8B%E5%8A%A1%E7%9A%84%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E6%9C%89%E5%93%AA%E4%BA%9B 事务特性(ACID) 原子性(Atomicity): 事务是原子的&…

CUDA C:核函数、主机函数、设备函数

相关阅读 CUDA Chttps://blog.csdn.net/weixin_45791458/category_12530616.html?spm1001.2014.3001.5482 核函数(Kernel Function)指的是在主机(CPU)调用(某些情况下也可以在设备调用),在设备(GPU)上执行的函数,使用__global__…

YOLOv8改进 | Conv篇 | 全新的SOATA轻量化下采样操作ADown(参数量下降百分之二十,附手撕结构图)

一、本文介绍 本文给大家带来的改进机制是利用2024/02/21号最新发布的YOLOv9其中提出的ADown模块来改进我们的Conv模块,其中YOLOv9针对于这个模块并没有介绍,只是在其项目文件中用到了,我将其整理出来用于我们的YOLOv8的项目,经过实验我发现该卷积模块(作为下采样模块)…

CentOS 6.5安装配置SVN服务器

​项目要用SVN来管理,所以需要给服务器安装SVN服务器端。 这里仅使用svn://协议来访问SVN服务器,不启用sasl。 客户端系统都是Windows,使用起来很简单,这里就不用说了。 本文仅针对1.6.11版本。在1.7.14版本上测试时,…

liunx前后端分离项目部署

文章目录 1、nginx的安装和自启动2.nginx负载均衡3.前后端项目部署-后端部署4.前后端项目部署-前端部署 1、nginx的安装和自启动 yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel1.安装我们nginx所需要的依赖 wget http://nginx.org/download/nginx-1.…

Open3D 点云法向量计算与可视化 (25)

Open3D 点云法向量计算与可视化 (25) 一、算法原理二、算法实现三、可视化显示和长度调节一、算法原理 通常计算点云的法向量可以使用以下两种常见的方法: 最小二乘法(Least Squares Method):该方法通过拟合局部表面的平面来计算法向量。对于给定点周围的邻域,可以通过…

故障排除:Failed to load SQL Modules into database Cluster

PostgreSQL 安装和故障排除 重新安装前的准备工作 在重新安装 PostgreSQL 之前,确保完成以下步骤: 重新卸载 PostgreSQL 并重启电脑。 删除以下目录: C:\Program Files\PostgreSQL\13C:\Users\admin\AppData\Roaming\pgadmin 重启安装过…

Vue2:router-link的replace属性

一、情景说明 我们在用浏览器访问网站的时候 知道浏览器会记录访问的历史路径,从而,可以退回到之前的页面 那么,Vue项目中的路由组件,通过router-link跳转,也是可以退回的 这里,我们用replace来屏蔽退回的…

【计算机网络】传输层——TCP和UDP详解

文章目录 一. TCP和UDP简介二. UDP 协议详解1. UDP报文格式2. UDP的使用场景 三. TCP 协议详解1. TCP报文格式2. TCP协议的重要机制确认应答(保证可靠传输的最核心机制)超时重传连接管理(三次握手、四次挥手)!&#xf…

内网设备如何在互联网上能访问

应用场景 设备安装到了客户现场,如果要调试设备,当前的处理方式是技术人员出差到客户现场、让客户开通VPN、让客户安装远程工具,远程到客户计算机上进行调试等方法。人不在家里想远程家里的电脑,当前处理方式就是在家里电脑上安装…

【信息提取】FindSomething 浏览器插件

下载地址 FindSomething 浏览器插件 概述 在网页的源代码或js中找到一些有趣的东西 FindSomething 用于快速在网页的html源码或js代码中提取一些有趣的信息,包括可能请求的资源、接口的url,可能请求的ip和域名,泄漏的证件号、手机号、邮箱…

Java多线程面试题(一)

Java多线程面试题(一) 前言1、在 Java 中守护线程和本地线程区别?2、线程与进程的区别?3、什么是多线程中的上下文切换?4、死锁与活锁的区别,死锁与饥饿的区别?5、Java 中用到的线程调度算法是什…

【Android12】Monkey压力测试源码执行流程分析

Monkey压力测试源码执行流程分析 Monkey是Android提供的用于应用程序自动化测试、压力测试的测试工具。 其源码路径(Android12)位于 /development/cmds/monkey/部署形式为Java Binary # development/cmds/monkey/Android.bp // Copyright 2008 The Android Open Source Proj…

Leetcoder Day21| 回溯理论基础+组合

语言:Java/Go 回溯理论基础 回溯函数也就是递归函数; 所有回溯法的问题都可以抽象为树形结构; 回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度,都构成的树的深度。 适用的题…

深度学习基础(一)神经网络基本原理

之前的章节我们初步介绍了机器学习相关基础知识,目录如下: 机器学习基础(一)理解机器学习的本质-CSDN博客 机器学习基础(二)监督与非监督学习-CSDN博客 机器学习基础(四)非监督学…