在Go中使用TTL选项进行映射

mat*_*.co 9 timeout go ttl data-structures

我需要构建一个这样的数据结构:

map[string]SomeType 
Run Code Online (Sandbox Code Playgroud)

但它必须存储大约10分钟的值,然后从内存中清除它.第二个条件是记录数量 - 它必须是巨大的.此数据结构必须每秒至少添加2-5K记录.

那么,Go中最正确的方法是什么?

我正在尝试为每个新元素制作goroutine超时.和一个(或更多)垃圾收集器goroutine与通道接收超时和清除元素.但我不确定这是最明确的方式.拥有数百万等待超时的goroutine是否可以?

谢谢.

One*_*One 19

您必须创建一个结构来保存地图并提供自定义的get/put/delete功能来访问它.

请注意,每秒2-5k次访问实际上并不是那么多,所以您不必担心这一点.

这是一个简单的实现:

type item struct {
    value      string
    lastAccess int64
}

type TTLMap struct {
    m map[string]*item
    l sync.Mutex
}

func New(ln int, maxTTL int) (m *TTLMap) {
    m = &TTLMap{m: make(map[string]*item, ln)}
    go func() {
        for now := range time.Tick(time.Second) {
            m.l.Lock()
            for k, v := range m.m {
                if now.Unix() - v.lastAccess > int64(maxTTL) {
                    delete(m.m, k)
                }
            }
            m.l.Unlock()
        }
    }()
    return
}

func (m *TTLMap) Len() int {
    return len(m.m)
}

func (m *TTLMap) Put(k, v string) {
    m.l.Lock()
    it, ok := m.m[k]
    if !ok {
        it = &item{value: v}
        m.m[k] = it
    }
    it.lastAccess = time.Now().Unix()
    m.l.Unlock()
}

func (m *TTLMap) Get(k string) (v string) {
    m.l.Lock()
    if it, ok := m.m[k]; ok {
        v = it.value
        it.lastAccess = time.Now().Unix()
    }
    m.l.Unlock()
    return

}
Run Code Online (Sandbox Code Playgroud)

playground

  • 另一个解决方案是保留地图和链接列表。链表包含(键、时间戳)对。您从后面推动并从前面获取,因此按键是按时间排序的,并且可以非常快地知道哪些按键可以移除。如果您设置正确的睡眠持续时间,甚至可以是瞬时的。这会使用更多内存,但速度会更快。 (2认同)

Kav*_*ian 5

看看buntdb

tinykv 不再维护。

只是为了记录,我遇到了同样的问题并编写了在内部使用地图的tinykv包。

  • 它使用一堆time.Time超时,因此它不会覆盖整个地图。
  • 创建实例时可以设置最大间隔。但是time.Duration,根据超时的最后一项,检查超时的实际间隔可以是大于零且小于最大值的任何值。
  • 它提供CASTake功能。
  • 可以设置回调(可选),通知哪个键和值超时。
  • 超时可以是显式的或滑动的。