multithreading - 引用计数资源的线程安全映射

标签 multithreading go concurrency hashmap hashtable

<分区>

关于管理资源集合:

  1. 可通过全局列表(例如 HashMap )按名称访问
  2. 从多个线程同时访问
  3. 引用计数(Golang 缺少“弱引用”;参见
    https://groups.google.com/forum/#!topic/golang-nuts/PYWxjT2v6ps)

例子:

var theList tMap // global

// in thread A, B, C etc
  aThing := theList.ref("aThing") // if exists then refcount++, else insert
  // use aThing
  theList.unref("aThing") // refcount--, if 0 then remove

编辑:我希望为此找到推荐的模式,但没有找到任何结果。所以我想到了这个:

type tMap struct {
   set map[string]*tMapSet
   updt sync.RWMutex
}

type tMapSet struct {
   ...
   refcount int32
}

func (o *tMap) ref(iId string) *tMapSet {
   o.updt.RLock()
   aSet := o.set[iId]
   if aSet != nil {
      atomic.AddInt32(&aSet.refcount, 1)
   }
   o.updt.RUnlock()

   if aSet == nil {
      o.updt.Lock()
      if aTemp := o.set[iId]; aTemp != nil {
         aSet = aTemp
         aSet.refcount++
      } else {
         aSet = &tMapSet{refcount:1}
         o.set[iId] = aSet
      }
      o.updt.Unlock()
   }
   return aSet
}

func (o *tMap) unref(iId string) {
   o.updt.RLock()
   aSet := o.set[iId]
   aN := atomic.AddInt32(&aSet.refcount, -1) // crash if set[iId] not found
   o.updt.RUnlock()

   if aN == 0 {
      o.updt.Lock()
      if aSet.refcount == 0 {
         delete(o.set, iId)
      }
      o.updt.Unlock()
   }
}

改进上述内容的清晰度或简洁性的建议?

最佳答案

只需将您的 map 包裹在互斥量中以保护访问(如果大量读取和少量写入,您也可以使用 RWMutex,可能数据也应该存储具体类型)。像这样的一些方法就可以了:

type MagicMap struct {
    sync.Mutex
    data   map[string]interface{}
    counts map[string]int
}

func (m MagicMap) Get(key string) interface{} {
  m.Lock()
  defer m.Unlock()
  return m.data[key]
}

func (m MagicMap) Add(key string, value interface{}) {
    m.Lock()
    m.data[key] = value
    m.counts[key] = m.counts[key] + 1
    m.Unlock()
}

func (m MagicMap) Remove(key string) {
    m.Lock()
    count := m.counts[key]
    count -= 1
    if count < 1 {
      delete(m.data, key)
      delete(m.counts, key)
    } else {
      m.counts[key] = count
    }
    m.Unlock()
}

这是未经测试的,写得很快,可能有错误,但希望能给你一个尝试的方向。如果你愿意,你可以只用一张带有 map[mystruct]int 的 map 来存储结构和计数。该示例具有单独的键和值。

https://play.golang.org/p/9k1lNRpqua

这是使用互斥锁保护 map 访问的另一个示例:

https://gobyexample.com/mutexes

你也可以在 Go 1.9 中使用新的 sync.Map,但它比只使用互斥体要慢。

关于multithreading - 引用计数资源的线程安全映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45624115/

相关文章:

go - 为什么 go fmt 允许空括号?

android - 一项并发服务或多项服务

python - 使用 Tkinter 时如何并行化方法

c# - 丢失的线程会怎样?

Android 为什么这不会抛出错误的线程异常?

regex - Go regex,Negative Look Ahead 替代方案

go - 仅在 kubernetes/CoreOS 上的 Go 中无效的 header 字段值

C-伪shell和并发

python - 停止 celery 工作人员从所有队列中消费

c# - 在完成线程之前等待 FileSystemWatcher 事件触发