go语言协程安全map
前言:
在go语言中 map 是很重要的数据结构。Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。问题来了,这么安逸的 数据结构,它不是协程安全的 !当多个 协程同时对一个map 进行 读写时,会抛出致命错误。总结一下 想要 做到 协程安全 map 一共有以下三种方法。
1.map + 锁
这是最常见的一种操作,当要对 map操作的时候就加锁,其他的 协程就等待。下面是代码示例:
package util import "sync" type SafeMap struct {
Data map[string]interface{}
Lock sync.RWMutex
} func (this *SafeMap) Get(k string) interface{} {
this.Lock.RLock()
defer this.Lock.RUnlock()
if v, exit := this.Data[k]; exit {
return v
}
return nil
} func (this *SafeMap) Set(k string, v interface{}) {
this.Lock.Lock()
defer this.Lock.Unlock()
if this.Data == nil {
this.Data = make(map[string]interface{})
}
this.Data[k] = v
}
2. sync.map
这个是go 最近版本新推出来的 协程安全 map == 可能是官方也觉得 蛮有必要的吧 。下面的代码 主要写一下使用方法。具体原理我就不介绍了。这里要注意一下 sync.map 不需要 初始化
var test sync.Map //设置元素
func set (k,v interface{}){
test.Store(k,v)
} //获得元素
func get (k interface{}) interface{}{
tem ,exit := test.Load(k)
if exit {
return tem
}
return nil
} //传入一个 函数 ,sync.map 会内部迭代 ,运行这个函数
func ranggfunc (funcs func(key, value interface{}) bool) {
test.Range(funcs)
} //删除元素
func del(key interface{}){
test.Delete(key)
}
3.单协程操作 map ,用 channle 通信
这个思路有点 骚,就是一直由一个协程 操作map ,其他协程 通过 channle 告诉这个协程应该 怎么操作。其实这样子 性能不是很好,因为 channle 底层 也是锁 ,而且 map 存数据 是要 计算hash的 ,之前是 多个协程自己算自己的hash ,现在变成了一个协程计算了。但是这个思路还是可以,不仅仅是 在 map上可以这么操作。socket 通信啊, 全局 唯一对象的调用啊,都可以用此思路。下面给大家看一下我是实现的代码:
package main import (
"fmt"
//"time"
) var (
ADD interface{} = 1
DEL interface{} = 2
GET interface{} = 3
) type safeMap struct {
Msq chan *[3] interface{} //['type','id','value',channle]
data map[interface{}]interface{}
chanl chan interface{}
} func NewSafeMap() *safeMap {
tem := &safeMap{}
tem.init()
return tem
} func (this *safeMap) init() {
this.Msq = make(chan *[3]interface{},10)
this.data = make(map[interface{}]interface{})
this.chanl = make(chan interface{},0)
go this.run()
} func (this *safeMap) run() {
for {
select {
case msg := <- this.Msq :
switch msg[0] {
case ADD :
this.dataAdd(msg[1],msg[2])
case DEL :
this.dataDel(msg[1])
case GET :
this.dataGet(msg[1])
}
}
}
} func (this *safeMap) msqChan (typ,id,val interface{}) *[3]interface{}{
return &[...]interface{}{typ,id,val}
} //保存 或者更新元素
func (this *safeMap) dataAdd (id , value interface{}) {
this.data[id] = value
} //删除元素
func (this *safeMap) dataDel (id interface{}) {
delete(this.data,id)
} //获得元素
func (this *safeMap) dataGet (id interface{}) {
if val ,exit := this.data[id] ;exit {
this.chanl <- val
return
}
this.chanl <- nil
} //----------------------------------------------------对外接口--------------------------------
func (this *safeMap) Add (id ,value interface{}) {
this.Msq <- this.msqChan(ADD,id,value)
} func (this *safeMap) Del (id interface{}) {
this.Msq <- this.msqChan(DEL,id ,nil)
} func (this *safeMap) Get (id interface{}) interface{} {
this.Msq <- this.msqChan(GET,id,nil)
res := <- this.chanl
return res
} //获得 长度
func (this *safeMap) GetLength() uint32{
return uint32(len(this.data))
} func main() {
sa := NewSafeMap() // sa.Add(1,1)
sa.Add(2,3)
fmt.Println(2,sa.Get(2))
sa.Del(2)
fmt.Println(2,sa.Get(2))
}
go语言协程安全map的更多相关文章
- Go语言协程
协程的特点 1.该任务的业务代码主动要求切换,即主动让出执行权限 2.发生了IO,导致执行阻塞(使用channel让协程阻塞) 与线程本质的不同 C#.java中我们执行多个线程,是通过时间片切换来进 ...
- 一个“蝇量级” C 语言协程库
协程(coroutine)顾名思义就是“协作的例程”(co-operative routines).跟具有操作系统概念的线程不一样,协程是在用户空间利用程序语言的语法语义就能实现逻辑上类似多任务的编程 ...
- Go语言协程并发---条件变量
package main import ( "fmt" "sync" "time" ) func main() { //要监听的变量 bit ...
- Go语言协程并发---读写锁sync.RWMutex
package main import ( "fmt" "sync" "time" ) /* 读写锁 多路只读 一路只写 读写互斥 */ / ...
- Go语言协程并发---互斥锁sync.Mutex
package main import ( "fmt" "sync" "time" ) /* mt.Lock() 抢锁 一次只能被一个协程锁 ...
- Go语言协程并发---等待组sync.WaitGroup
package main import ( "fmt" "sync" "time" ) /*等待组API介绍*/ func main071( ...
- Go语言协程并发---管道信号量应用
package main import ( "fmt" "math" "strconv" "time" ) /* ·10 ...
- Go语言协程并发---生产者消费者实例
package main import ( "fmt" "strconv" "time" ) /* 改进生产者消费者模型 ·生产者每秒生产一 ...
- Go语言协程并发---原子操作
package main import ( "fmt" "sync/atomic" ) /* 用原子来替换锁,其主要原因是: 原子操作由底层硬件支持,而锁则由操 ...
随机推荐
- map的key排序
java map的key排序吗 java为数据结构中的映射定义了一个接口java.util.Map,他实现了四个类,分别是:HashMap,HashTable,LinkedHashMapTreeMap ...
- spring boot:接口站增加api版本号后的安全增强(spring boot 2.3.3)
一,接口站增加api版本号后需要做安全保障? 1,如果有接口需要登录后才能访问的, 需要用spring security增加授权 2,接口站需要增加api版本号的检验,必须是系统中定义的版本号才能访问 ...
- 运行bee run之后出现的错误以及解决方法Failed to build the application:
运行bee run之后出现的错误以及解决方法 创建一个beego项目 bee new myapp 在该项目执行下面的代码 bee run 出现的问题 2020/04/22 21:12:07 INF ...
- centos8:linux平台查看线程(ps/pstree/top)
一,ps/pstree/top命令所属的rpm包 pstree所属的包 [root@blog ~]# whereis pstree pstree: /usr/bin/pstree /usr/bin/p ...
- centos8上安装ImageMagick6.9.10并压缩图片生成webp缩略图
一,ImageMagick的作用: ImageMagick 是一个用来创建.编辑.合成图片的软件. 它可以读取.转换.写入多种格式的图片. 功能包括:图片切割.颜色替换.各种效果的应用, 图片的旋转. ...
- phpexcel导出数据 出现Formula Error的解决方案
phpexcel导出数据报错 Uncaught exception 'Exception' with message 'Sheet1!A1364 -> Formula Error: Unexpe ...
- 基于ECS搭建云上博客
场景介绍 本文为您介绍如何基于ECS搭建云上博客. 背景知识 本场景主要涉及以下云产品和服务: 云服务器ECS 云服务器(Elastic Compute Service,简称ECS)是阿里云提供的性能 ...
- 【Vue.js】简单说下vuejs中v-model自定义使用姿势
vue.js中有个v-model的语法,可以实现双向绑定. 起初刚看到的时候,觉得很神奇.后面随着对vue.js的熟悉.发现这个其实是vue官方给我们实现的一个语法糖. 使用v-model的时候,vu ...
- drf (学习第三部)
目录 视图 视图额基类 视图类扩展 GenericAPIView的视图子类 视图集ViewSet 路由Routers 视图 Django REST framework 提供的视图的主要作用: 控制序列 ...
- 如何利用go-zero在Go中快速实现JWT认证
关于JWT是什么,大家可以看看官网,一句话介绍下:是可以实现服务器无状态的鉴权认证方案,也是目前最流行的跨域认证解决方案. 要实现JWT认证,我们需要分成如下两个步骤 客户端获取JWT token. ...