欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

golang线程安全的map实现

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

网上找的协程安全的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地址:

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