golang线程安全的map实现

 更新时间:2019年03月11日 10:11:13   作者:hackssssss  
这篇文章主要介绍了golang线程安全的map实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

网上找的协程安全的map都是用互斥锁或者读写锁实现的,这里用单个协程来实现下,即所有的增删查改操作都集成到一个goroutine中,这样肯定不会出现多线程并发访问的问题。

基本思路是后台启动一个长期运行的goroutine,阻塞的接受自己channel中的请求req,req分为不同的请求,比如读key,写key等,然后在这个goroutine中进行各种操作。

例: Get方法向readSig(channel)中发送一条请求。请求是readReq的指针,当run方法接收到信号时,读取底层map,将值写入readReq的value中(value是个channel),Get方法阻塞的接收value,接收到就返回value。

ps:花了两个多小时写完,只是简单的做了测试,没有深入测试,另外性能也没有测过,以后有空会深入测试一下正确性以及相比加锁的写法其性能如何。

package util
 
type smap struct {
 m      map[interface{}]interface{}
 readSig   chan *readReq
 writeSig   chan *writeReq
 lenSig    chan *lenReq
 terminateSig chan bool
 delSig    chan *delReq
 scanSig   chan *scanReq
}
 
type readReq struct {
 key  interface{}
 value interface{}
 ok  chan bool
}
 
type writeReq struct {
 key  interface{}
 value interface{}
 ok  chan bool
}
 
type lenReq struct {
 len chan int
}
 
type delReq struct {
 key interface{}
 ok chan bool
}
 
type scanReq struct {
 do     func(interface{}, interface{})
 doWithBreak func(interface{}, interface{}) bool
 brea    int
 done    chan bool
}
// NewSmap returns an instance of the pointer of safemap
func NewSmap() *smap {
 var mp smap
 mp.m = make(map[interface{}]interface{})
 mp.readSig = make(chan *readReq)
 mp.writeSig = make(chan *writeReq)
 mp.lenSig = make(chan *lenReq)
 mp.delSig = make(chan *delReq)
 mp.scanSig = make(chan *scanReq)
 go mp.run()
 return &mp
}
 
//background function to operate map in one goroutine
//this can ensure that the map is Concurrent security.
func (s *smap) run() {
 for {
 select {
 case read := <-s.readSig:
  if value, ok := s.m[read.key]; ok {
  read.value = value
  read.ok <- true
  } else {
  read.ok <- false
  }
 case write := <-s.writeSig:
  s.m[write.key] = write.value
  write.ok <- true
 case l := <-s.lenSig:
  l.len <- len(s.m)
 case sc := <-s.scanSig:
  if sc.brea == 0 {
  for k, v := range s.m {
   sc.do(k, v)
  }
  } else {
  for k, v := range s.m {
   ret := sc.doWithBreak(k, v)
   if ret {
   break
   }
  }
  }
  sc.done <- true
 case d := <-s.delSig:
  delete(s.m, d.key)
  d.ok <- true
 case <-s.terminateSig:
  return
 }
 }
}
 
//Get returns the value of key which provided.
//if the key not found in map, ok will be false.
func (s *smap) Get(key interface{}) (interface{}, bool) {
 req := &readReq{
 key: key,
 ok: make(chan bool),
 }
 s.readSig <- req
 ok := <-req.ok
 return req.value, ok
}
 
//Set set the key and value to map
//ok returns true indicates that key and value is successfully added to map
func (s *smap) Set(key interface{}, value interface{}) bool {
 req := &writeReq{
 key:  key,
 value: value,
 ok:  make(chan bool),
 }
 s.writeSig <- req
 return <-req.ok //TODO 暂时先是同步的,异步的可能存在使用方面的问题。
}
 
//Clear clears all the key and value in map.
func (s *smap) Clear() {
 s.m = make(map[interface{}]interface{})
}
 
//Size returns the size of map.
func (s *smap) Size() int {
 req := &lenReq{
 len: make(chan int),
 }
 s.lenSig <- req
 return <-req.len
}
 
//terminate s.Run function. this function is usually called for debug.
//after this do NOT use smap again, because it can make your program block.
func (s *smap) TerminateBackGoroutine() {
 s.terminateSig <- true
}
 
//Del delete the key in map
func (s *smap) Del(key interface{}) bool {
 req := &delReq{
 key: key,
 ok: make(chan bool),
 }
 s.delSig <- req
 return <-req.ok
}
 
//scan the map. do is a function which operate all of the key and value in map
func (s *smap) EachItem(do func(interface{}, interface{})) {
 req := &scanReq{
 do:  do,
 brea: 0,
 done: make(chan bool),
 }
 s.scanSig <- req
 <-req.done
}
 
//scan the map util function 'do' returns true. do is a function which operate all of the key and value in map
func (s *smap) EachItemBreak(do func(interface{}, interface{}) bool, condition bool) {
 req := &scanReq{
 doWithBreak: do,
 brea:    1,
 done:    make(chan bool),
 }
 s.scanSig <- req
 <-req.done
}
 
//Exists checks whether the key which provided is exists in map
func (s *smap) Exists(key interface{}) bool {
 if _,found := s.Get(key); found {
 return true
 }
 return false
}

github地址:https://github.com/hackssssss/safemap

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • go语言的初始化顺序,包,变量,init详解

    go语言的初始化顺序,包,变量,init详解

    这篇文章主要介绍了go语言的初始化顺序,包,变量,init详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Go结合Gin导出Mysql数据到Excel表格

    Go结合Gin导出Mysql数据到Excel表格

    本文主要介绍了Go结合Gin导出Mysql数据到Excel表格,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • Golang 使用http Client下载文件的实现方法

    Golang 使用http Client下载文件的实现方法

    今天小编就为大家分享一篇Golang 使用http Client下载文件的实现方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07
  • Golang为什么占用那么多的虚拟内存原理解析

    Golang为什么占用那么多的虚拟内存原理解析

    这篇文章主要介绍了Golang为什么占用那么多的虚拟内存原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • 浅谈golang类型断言,失败类型断言返回值问题

    浅谈golang类型断言,失败类型断言返回值问题

    这篇文章主要介绍了浅谈golang类型断言,失败类型断言返回值问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • 一文详解Go语言中的Option设计模式

    一文详解Go语言中的Option设计模式

    这篇文章主要为大家详细介绍了Go语言中Option设计模式的相关知识,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的可以了解一下
    2023-05-05
  • Golang Cron 定时任务的实现示例

    Golang Cron 定时任务的实现示例

    这篇文章主要介绍了Golang Cron 定时任务的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • Go ORM的封装解决方式详解

    Go ORM的封装解决方式详解

    这篇文章主要为大家介绍了Go ORM的封装解决方式详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • Go语言实现请求超时处理的方法总结

    Go语言实现请求超时处理的方法总结

    这篇文章主要为大家详细介绍了Go语言中实现请求的超时控制的方法,主要是通过timer和timerCtx来实现请求的超时控制,希望对大家有所帮助
    2023-05-05
  • Go语言流程控制详情

    Go语言流程控制详情

    这篇文章主要介绍了Go语言流程控制详情,流程控制包含分三大类:条件判断,循环控制和无条件跳转。下面关于更多相关内容需要的小伙伴可以参考一下
    2022-03-03

最新评论