博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【Go语言】map在goroutine通信中的使用问题
阅读量:6527 次
发布时间:2019-06-24

本文共 2647 字,大约阅读时间需要 8 分钟。

简介

本篇文章的主要内容是解决go语言map在使用中遇到的两个问题,对于初学者是不可避免的坑

一、cannot assign to struct field

当map中存在struct类型的成员,如果在初始化后,再次对其进行修改,就会出现这种错误。

type student struct {    name string    age int}var testMap = map[string]student{    "xiao":{
"xiao", 18}, "long":{
"long", 19}, "ren": {
"ren" , 20},}func main(){ testMap["xiao"].name = "da"}

以上执行过程,即我们对于元素修改的惯用思路,直接访问数据项,对于其进行修改。但在go build的过程中,会报错:cannot assign to struct field。

因为map并非是一个并发安全的结构,因此不可以直接修改其中涉及到struct的相关性。难道map初始化就无法修改了吗?答案是否定,只是修改的方式比较特殊。

对于上述问题的有两种解决方案

1、不修改原有map的结构,达到修改数据项的目的。

如果想要修改map中struct的某一项的内容,就要修改整个struct的内容,重新赋予key的value。

func main() {    testMap["xiao"] = student{        name: "da",        age:  testMap["xiao"].age,    }}

对于其中不需要改变的数据项采用原始数据,对于需要修改的数据项采用新数据。

2、修改原有map的结构,达到修改数据项的目的。

将map定义中的struct项设定为地址的形式。

var testMap = map[string] *student{    "xiao": {
"xiao", 18}, "long": {
"long", 19}, "ren": {
"ren", 20},}

将其改为指针的形式,map就可以直接修改struct中数据项了。

func main() {    testMap["xiao"].name = "da"}

此时go build进行编译就不会报任何错了。建议采用第2种解决方案,符合日常的操作习惯。

 

二、fatal error:concurrent map read and map write

如果map由多goroutine同时进行读写操作,就会出现fatal error:concurrent map read and map write错误。

因为map并不像chan,对于goroutine的同步访问是安全的,map为引用类型,即使是函数调用,也不会产生多个副本,因此对于多个goroutine的访问,实际上是对同一块内存进行访问。基于我们对临界资源的认识,如果不加任何限制的对map进行访问,map共享资源就会遭到破坏并报错,这种错误也不是固定的,而是随机的,因为并不是每次对map的操作都会引起这种错误。

针对上述错误,一般有如下两种解决方案。

1、加锁

go语言sync包中实现了两种锁Mutex(互斥锁)和RWMutex(读写锁),其中RWMutex是基于Mutex实现的。

(1)互斥锁

type Mutex    func (m *Mutex) Lock()    func (m *Mutex) Unlock()

其中Lock()加锁,Unlock解锁,成对进行使用,否则会panic。使用Lock()加锁后,便不能再次对其进行加锁,直到利用Unlock解锁。对于使用读写锁的资源,每次只能有一个goroutine对其进行访问,适用于读写操作没有明显区别的场景。

对map使用互斥锁举例。

type Demo struct {    Data map[string]string    Lock sync.Mutex}func (d Demo) Get(k string) string{    d.Lock.Lock()    defer d.Lock.Unlock()    return d.Data[k]}func (d Demo) Set(k,v string) {    d.Lock.Lock()    defer d.Lock.Unlock()    d.Data[k]=v}

2、读写锁

type RWMutex    func (rw *RWMutex) Lock()    func (rw *RWMutex) RLock()    func (rw *RWMutex) RLocker() Locker    func (rw *RWMutex) RUnlock()    func (rw *RWMutex) Unlock()

RWMutex为读写锁,该锁可以对某个资源加多个读锁或者一个写锁,适用于读次数远大于写次数的场景。

注(1)其中写锁RLock()的优先级要高于读锁Lock(),当有写锁请求时,读请求就阻塞,直到没有写锁或者没有锁时,才会加载读锁。

(2)读写锁都是成对使用的,并且加锁要在解锁前使用,否则会panic或者fatal error。

对map使用读写锁举例。

type Demo struct {    Data map[string]string    Lock sync.RWMutex}func (d Demo) Get(k string) string{    d.Lock.RLock()    defer d.Lock.RUnlock()    return d.Data[k]}func (d Demo) Set(k,v string) {    d.Lock.Lock()    defer d.Lock.Unlock()    d.Data[k]=v}

2、利用channel串行化处理

能使用chan的场景,推荐使用chan进行goroutine的交互。chan自身的机制,保证数据访问的高效性和正确性。

 参考链接:

 

转载于:https://www.cnblogs.com/longcnblogs/p/9678393.html

你可能感兴趣的文章
C# 语言历史版本特性(C# 1.0到C# 7.1汇总更新)
查看>>
什么是数据埋点?
查看>>
git回滚
查看>>
vue2.0 引用qrcode.js实现获取改变二维码的样式
查看>>
Python 判断闰年,判断日期是当前年的第几天
查看>>
web.xml 中的listener、 filter、servlet 加载顺序
查看>>
MyBatis原理简介和小试牛刀
查看>>
js部分基础
查看>>
脏读,幻读,不可重复读解释和例子
查看>>
Tomcat指定(JDK路径)JAVA_HOME而不用环境变量
查看>>
银行卡信息安全事件频发 互联网站成数据泄露"重灾区"
查看>>
云服务器 ECS 使用OpenAPI管理ECS:使用OpenAPI弹性创建ECS实例
查看>>
写个软件来防止服务器网站CPU百分百
查看>>
智能城市里,“公共电话亭”的存在意味着什么?
查看>>
JVM分代垃圾回收策略的基础概念
查看>>
5G技术的5大猜想
查看>>
MongoDB 3.0(1):CentOS7 安装MongoDB 3.0服务
查看>>
别随便安装 Pokemon GO被曝藏恶意后门
查看>>
让数据会思考会说话,为出海企业提供多样化数据智能解决方案
查看>>
我眼中的自动化测试框架设计要点
查看>>