网上找的协程安全的地图都是用互斥锁或者读写锁实现的,这里用单个协程来实现下,即所有的增删查改操作都集成到一个goroutine中,这样肯定不会出现多线程并发访问的问题。
基本思路是后台启动一个长期运行的goroutine,阻塞的接受自己通道中的请求要求,要求分为不同的请求,比如读键,写键等,然后在这个goroutine中进行各种操作。
例:方法向readSig(渠道)中发送一条请求。请求是readReq的指针,当运行方法接收到信号时,读取底层地图,将值写入readReq的中值(值是个频道),得到方法阻塞的接收值,接收到就返回价值。
ps:花了两个多小时写完,只是简单的做了测试,没有深入测试,另外性能也没有测过,以后有空会深入测试一下正确性以及相比加锁的写法其性能如何。
包跑龙套 smap struct类型{ 米图{}{}][接口界面 readSig陈* readReq writeSig陈* writeReq lenSig陈* lenReq 陈terminateSig bool delSig陈* delReq scanSig陈* scanReq } readReq struct类型{ 关键界面{} 价值界面{} 好的陈bool } writeReq struct类型{ 关键界面{} 价值界面{} 好的陈bool } lenReq struct类型{ int len陈 } delReq struct类型{ 关键界面{} 好的陈bool } scanReq struct类型{ func(接口界面{},{}) doWithBreak func(接口界面{},{})保龄球 沥青int 做陈bool }//新闻地图返回safemap的指针的一个实例 func新闻地图()* smap { var议员smap mp。m=使(map接口(接口{}){}) mp。readSig=使(陈* readReq) mp。writeSig=使(陈* writeReq) mp。lenSig=使(陈* lenReq) mp.delSig=使(陈* delReq) mp。scanSig=使(陈* scanReq) 去mp.run () 返回,议员 }//背景函数操作在一个goroutine地图//这个地图可以确保并发安全。 func (s * smap) run () { 为{ 选择{ 案例阅读:=& lt; -s.readSig: 如果价值,好的:=s.m [read.key];好{ 阅读。值=https://www.yisu.com/zixun/value 阅读。好<-真实 其他}{ 阅读。好<-假 } 案例编写:=<-s.writeSig: s.m[写。关键]=write.value 写。好<-真实 l:=<-s.lenSig: llen <- len(小) sc:=<-s.scanSig: 如果sc.brea==0 { 对于k、v:=范围。m { sc.do (k、v) } 其他}{ 对于k、v:=范围。m { ret:=sc.doWithBreak (k、v) 如果ret { 打破 } } } sc.done <-真实 例d:=<-s.delSig: 删除(s。米,d.key) d。好<-真实 情况下<-s.terminateSig: 返回 } } }//返回键提供的价值。//如果键中没有地图,好将是错误的。 func (s * smap)得到(关键接口{})(接口{},bool) { 点播:=&readReq { 关键:钥匙, 好:使(陈bool), } 年代。readSig <-请求 ok:=<-req.ok 返回请求。值,好 }//设置设置映射的键和值//返回true表明,键和值是成功添加到地图 func (s * smap)集({})键界面{},值接口bool { 点播:=&writeReq { 关键:钥匙, 价值:价值, 好:使(陈bool), } 年代。writeSig <-请求 <要求返回。好吧//TODO暂时先是同步的,异步的可能存在使用方面的问题。 }//清除地图中的所有键和值。 func (s * smap) Clear () { 年代。m=使(map接口(接口{}){}) }//大小返回地图的大小。 int func (s * smap)大小(){ 点播:=&lenReq { len:陈(int), } 年代。lenSig <-请求 返回<-req.len }//终止。运行功能。这个函数通常是要求调试。//在此之后又不使用smap,因为它可以让你的程序块。 func (s * smap) TerminateBackGoroutine () { 年代。terminateSig <-真实 }//▽删除地图的关键 func (s * smap)德尔(关键接口{})bool { 点播:=&delReq { 关键:钥匙, 好:使(陈bool), } s.delSig <-请求 返回<-req.ok }//扫描地图。做的是一个函数的操作中所有的键和值地图吗 func (s * smap) EachItem (func(接口界面{},{})){ 点播:=&scanReq { 做的事:做什么, 沥青:0, 做:让(陈bool), } 年代。scanSig <-请求 <-req.done }//扫描地图util听函数返回true。做的是一个函数的操作中所有的键和值地图吗 func (s * smap) EachItemBreak(做func(接口界面{},{})bool,条件bool) { 点播:=,scanReq { doWithBreak:, 沥青:1、 做:让(陈bool), } 年代。scanSig & lt;——要求 & lt; -req.done }//检查是否存在提供的关键是存在于地图上 func (s * smap)存在(关键接口{})bool { 如果_,发现:=s.Get(关键);发现{ 还真 } 返回假 }golang线程安全地图的实现