关于GoLang的concurrent map writes错误_程序猿的世界-程序员宝宝

技术标签: 并发  concurrent  互斥  map异常  map  GoLang  

转载请附原链,搬砖繁忙回复不及时见谅,技术交流请加QQ群:909211071

作为一个GoLang萌新(其实就是并发编程萌新,之前一直在做PHP),对并发下共享资源的竞争了解不多。所以一开始写出了如下代码:

type OriginPriceController struct {
	OriginPriceService *origin_price_service.OriginPriceService
}


func (self *OriginPriceController) action() {
    var wg sync.WaitGroup
	wg.Add(2)
	go func() {
		defer wg.Done()
		self.Data["product"] = self.OriginPriceService.GetOriginPriceProduct(self.C, productId)
	}()

	go func() {
		defer wg.Done()
		self.Data["location"] = self.OriginPriceService.GetOriginPriceLocation(self.C, locationId)
	}()
	wg.Wait()
}

轻松搞定,并行请求数据,相比之前的串行,性能基本上提升一倍。本以为并发编程也不过如此,就起几个goroutine,用WaitGroup同步多个协程间的状态,等待所有协程都执行完即可。

原本以为这样就搞定了,其实代码中隐含着一个致命问题,当多次请求测试时,很快问题就暴露出来了:

fatal error: concurrent map writes

goroutine 164 [running]:
runtime.throw(0x17e99d3, 0x15)
        /usr/local/go/src/runtime/panic.go:774 +0x72 fp=0xc000069ee8 sp=0xc000069eb8 pc=0x102f6c2
runtime.mapassign_faststr(0x16fe080, 0xc000574150, 0x17e0ed5, 0x8, 0x0)
        /usr/local/go/src/runtime/map_faststr.go:291 +0x3fe fp=0xc000069f50 sp=0xc000069ee8 pc=0x1014d8e
gin-frame/controllers/first_origin_price.(*FirstOriginPriceController).action.func2(0xc00029e550, 0xc00014e180, 0x571)
        /Users/why/Desktop/go/gin-frame/controllers/first_origin_price/first_origin_price_controller.go:62 +0xc4 fp=0xc000069fc8 sp=0xc000069f50 pc=0x164e0d4
runtime.goexit()
        /usr/local/go/src/runtime/asm_amd64.s:1357 +0x1 fp=0xc000069fd0 sp=0xc000069fc8 pc=0x105cd81
created by gin-frame/controllers/first_origin_price.(*FirstOriginPriceController).action
        /Users/why/Desktop/go/gin-frame/controllers/first_origin_price/first_origin_price_controller.go:60 +0x156

没错,就是文章题目里提到的:concurrent map writes

原来Map,对于共享变量,资源,并发写会产生竞争, 共享资源遭到破坏,解决办法是拆分成两个局部变量用于接收goroutine,在goroutine执行完之后再将结果存入公共Map,相应代码如下:

    var wg sync.WaitGroup
	product := make(map[string]interface{})
	location := make(map[string]interface{})
	wg.Add(2)
	go func() {
		defer wg.Done()
		product = self.OriginPriceService.GetOriginPriceProduct(self.C, productId)
	}()

	go func() {
		defer wg.Done()
		location = self.OriginPriceService.GetOriginPriceLocation(self.C, locationId)
	}()
	wg.Wait()

	self.Data["product"] = product
	self.Data["location"] = location

 

还可以使用sync.Map解决,除了使用互斥量以外,还运用了原子操作,可以保证并发写安全,但是有可能出现锁race。

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/why444216978/article/details/107732602

智能推荐

ajax三级省联动_Leroi_Liu的博客-程序员宝宝

province.html部分: 省份: 请选择省份 市: 请选择市 县: 请选择县 //1 找provinces数据 $.ajax({ type:'post', data:{'parent_id':1,'regi

Tensilica支持Carbon的SOC Designer仿真平台_weixin_34015566的博客-程序员宝宝

Tensilica支持Carbon的SOC Designer仿真平台客户能够在Carbon公司虚拟平台建立Tensilica处理器模型2009-01-19点击:178自动创建、验证和实现系统级仿真模型的领先供应商Carbon Design Systems公司和领先的嵌入式可配置处理器内核供应商Tensilica公司日前宣布,已将Tensil...

CPLD 八段数码管时钟显示的VHDL实现_feiyunliu的博客-程序员宝宝

--/*******************************************************************-- *-- *    DESCRIPTION: UART transmitter module.-- *-- *    AUTHOR: -- *-- *    HISTORY: -- *-- *********************************

android+com.google.android.gms,无法找到com.google.android.gms:play-services:7.3.0_柴老师也很皮的博客-程序员宝宝

我有从Android Studio毕业的这个日志:Error:A problem occurred configuring project ':ParseStarterProject'.> Could not resolve all dependencies for configuration ':ParseStarterProject:_debugCompile'.> Could n...

多系统之路-安装顺序win10+ubuntu+win7_weixin_30410999的博客-程序员宝宝

一直都很想好好的安装多个系统基本知识一些名词的解释MBR分区表:MasterBootRecord,即硬盘主引导记录分区表,只支持容量在2.1TB以下的硬盘,超过2.1TB的硬盘只能管理2.1TB,最多只支持4个主分区或三个主分区和一个扩展分区,扩展分区下可以有多个逻辑分区。GPT分区表:GPT,全局唯一标识分区表(GUIDPartitionTable...

【转】最短路径——Dijkstra算法和Floyd算法_负雪明烛的博客-程序员宝宝

【转】最短路径——Dijkstra算法和Floyd算法标签(空格分隔): 算法本文是转载,原文在:最短路径—Dijkstra算法和Floyd算法注意:以下代码 只是描述思路,没有测试过!!Dijkstra 算法1.定义概览Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法

随便推点

python中的面向对象_老年python学习者的博客-程序员宝宝

1.什么是类?什么是对象?类是具有相同属性和技能一组对象的抽象对象是类实例化的结果,用来描述一个具体的事物比如猫是一个类,而我养的猫是一个对象2.创建一个猫类并实例化的代码class Cat(): def __init__(self,name,age,color): self.name = name self.age = age self.color = color def talk(self): print('%s

大数据平台核心技术-实验记录_月色很柔的博客-程序员宝宝_大数据平台核心技术

大数据核心平台技术-试验记录一、前言二、实验内容实验一 :Hadoop集群搭建三、实验过程记录2.1安装准备2.2 Hadoop集群搭建安装文件上传工具JDK安装Hadoop安装:Hadoop集群配置配置Hadoop集群主节点将集群主节点的配置文件分发到其他子节点一、前言学校:许昌学院学院:信息工程学院实验环境:操作系统:Linux (CentOS 6.7) JDK版本:1.8 (...

Jackson-databind 反序列化漏洞(CVE-2020-36179 ~ CVE-2020-36189)_ℳ₯㎕ddzོꦿ࿐的博客-程序员宝宝_jackson反序列化漏洞

2021年1月7日,jackson-databind官方发布安全通告,披露jackson-databind < 2.9.10.8存在多个反序列化远程代码执行漏洞(CVE-2020-36179 ~ CVE-2020-36189),利用该漏洞,攻击者可远程执行代码,控制服务器。2020年12月17日,jackson-databind官方发布安全通告,披露jackson-databind < 2.9.10.8存在反序列化远程代码执行漏洞(CVE-2020-35490/CVE-2020-35491).

暑假很忙_iteye_11687的博客-程序员宝宝

我是非计算机专业的计算机爱好者,我为自己的2009年暑假安排了很多事情:1.进一步提高C语言。2.学习Java。3.学习Jsp。4.准备程序员考试。5。学习C++。6.学习HTML。7.学习数据结构。8.学习SQL Server。9。学习Java Scprit。10.学习Photoshop。我肯定很充实,因为Ihave a dream !...

<java API源码初体验>4---collection集合之HashSet原理分析_Fuego801的博客-程序员宝宝

java的HashSet是由HashMap的key组成的,用的增删改查的方法均基于HashMap的key。根据HashMap保证了key的唯一性。 public boolean add(E e) { return map.put(e, PRESENT)==null; }它的add()方法,用的就是HashMap里面的put()方法。 若map中已存在e,则返回false;若

C#(Winform) 当前线程不在单线程单元中,因此无法实例化 ActiveX 控件_EricBBB的博客-程序员宝宝

解决方案:1、在主线程中实例化此ActiveX控件2、将创建此Active控件的线程设定为单线程。      Thread.ApartmentState 获取或设置此线程的单元状态。            newThread= new Thread(MainFormMessageThread);            newThread.SetApartmentState(S...

推荐文章

热门文章

相关标签