百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

浅谈 Golang 中数据的并发同步问题(三)—Map的并发问题

toyiye 2024-06-21 12:00 8 浏览 0 评论

Go语言中文网,致力于每日分享编码知识,欢迎关注我,会有意想不到的收获!

01

写在前面

过去 Web 开发的工作比较少涉及到并发的问题,每个用户请求在独立的线程里面进行,偶尔涉及到异步任务但是线程间数据同步模型非常简单,因此并未深入探究过并发这一块。最近在写游戏相关的服务端代码时发现数据的并发同步场景非常多,因此花了一点时间来探索。这是一个系列文章,本文为第三篇。

本文简单介绍 Golang 中 map 类型的安全使用。

02

Golang 中 map 的使用

在业务逻辑中保存 key-value 是一个非常普遍的需求,因此 Map 的使用场景非常多。

不允许并发读写的 map

在 Golang 源码实现中对 map 的要求比较高(见《 Go maps in action》):Maps are not safe for concurrent use: it's not defined what happens when you read and write to them simultaneously(当并发使用时 Maps 是不安全的,当并发地读写 map 的时候无法预知会发生啥 )。

如果不加保护地在不同的线程中读写 map 类型的数据,代码会直接崩溃并异常退出。比如下面的代码:

运行上面的代码可以得到下面类似的结果:

go run map/main.go 
# fatal error: concurrent map read and map write
# ....(省略异常堆栈)

从输出结果来看,Golang 运行时明确禁止 map 的并发读写,且在检测到这种情况后直接异常退出。这不同于其他数据类型,比如 int、string 等,对比下面的代码(说明:下面的代码存在隐形的并发问题,具体参考浅谈 Golang 中数据的并发同步问题(二)):

再次需要说明,虽然上面的代码在不同的线程中访问 int 类型的数据并未直接异常退出,但是这种不加任何安全措施的并发读写是存在安全风险的,具体参考

浅谈 Golang 中数据的并发同步问题(二)

安全使用 map——显而易见地加锁

既然 Golang 在运行时不允许对 map 的并发读写,当需要在多个线程中读写 map 时,显而易见的方式是加锁(如浅谈 Golang 中数据的并发同步问题(一)所描述的)。

下面的代码把 map 类型的 m 封装在一个匿名的 struct 中,同时整个匿名的 struct 继承了 sync.RWMutex 结构,因此拥有了 加读写锁 的功能,从而安全地实现了多个线程对 map 的 “并发读写”:

为什么 map 并发读写时会在运行时异常退出

最后提一下这个问题:为什么 int、string、slice 等变量在多个线程读写时运行正常,而 map 在多个线程并发读写时会运行时异常退出? 其实这个涉及到 map 的具体实现(我知道这是一句废话 +_+)。

简单来讲,可以从Go 源码中 map 运行时相关的部分 窥见一些依据:map 的增改删查可以分别对应到 func mapassign()、func mapaccess1()、func mapdelete()这几个函数,每个函数都有非常长的执行逻辑;如果多个线程并发读写同一个 map,大概率会出现 ① mapassign 函数(增加某个 key 的值)执行到一半的时候 mapaccess1 读取到一个相应的零值,② mapaccess1 函数(读取某个 key 的值)执行到一半的时候 mapdelete 已经删除了对应的 key,等等。

同时考虑到增删数据时底层数据的改变(比如扩容重分配,可以参考深度好文 | 面试大厂 Go 职位会问到的 map 知识点),因此保持 map 的单纯变得很重要;为避免出现难以 debug 的异常,运行时环境显式地并发异常退出也就可以理解了。

03

小结

Golang 的运行时会在 map 的增改删查过程中检测是否有并发读写的情况,当发现并发读写时直接异常退出。相对于其他数据类型(比如 int、string、slice 等),map 的并发使用是比较严苛的(安全&性能的折中);可以认为 map 的这种严苛很大程度上降低了诡异 bug 的产生,增加代码的鲁棒性。

最后,当提到 map 的并发使用时,很多时候会提到 sync.Map 的使用,不过由于它大量使用了 interface{} 类型,使用起来并不是那么方便;目前为止,我更喜欢加读写锁的方式来使用 map 而不是使用线程安全的 sync.Map

参考

  • 浅谈 Golang 中数据的并发同步问题(一) 介绍通过加锁的方式保证线程安全
  • 浅谈 Golang 中数据的并发同步问题(二) 介绍了 atomic 包的使用及其局限性
  • Go maps in action - The Go Blog 官方文档中介绍 map 的博客(需要自备梯子)
  • go语言坑之并发访问map 浅显易懂地介绍了 map 的坑及并发访问方法
  • 疫苗:Java HashMap的死循环 了解 Java 中 HashMap 的实现机制,可以知道 Map 的线程不安全的实现是一个普遍现象
  • src/runtime/map.go Go 源码中 map 相关的部分(运行时)
  • sync - The Go Programming Language Golang 官方 sync 包中包含线程安全的 sync.Map
  • go map的线程安全使用 介绍了 sync.Map 的使用

著作权归作者所有。

原文: https://jingwei.link/2019/05/12/golang-concurrency-03-map.html

本文作者:敬维,原创授权发布

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码