TOC

Golang 自动过期 Map

type ExpiringMap struct {
    m      sync.Map
    expiry time.Duration
}

func (e *ExpiringMap) set(key, value interface{}) {
    e.m.Store(key, value)

    go func() {
        time.Sleep(e.expiry)
        e.m.Delete(key)
    }()
}

改进:定时清理

package main

import (
    "sync"
    "time"
)

type Item struct {
    value      interface{}
    expiration int64
}

type ExpiringMap struct {
    m       sync.Mutex
    items   map[string]Item
    timeout time.Duration
}

func NewExpiringMap(timeout time.Duration) *ExpiringMap {
    em := &ExpiringMap{
        items:   make(map[string]Item),
        timeout: timeout,
    }
    go em.cleanup()
    return em
}

func (em *ExpiringMap) Set(key string, value interface{}) {
    em.m.Lock()
    defer em.m.Unlock()
    em.items[key] = Item{
        value:      value,
        expiration: time.Now().Add(em.timeout).UnixNano(),
    }
}

func (em *ExpiringMap) Get(key string) (interface{}, bool) {
    em.m.Lock()
    defer em.m.Unlock()
    item, found := em.items[key]
    if !found {
        return nil, false
    }
    if time.Now().UnixNano() > item.expiration {
        return nil, false
    }
    return item.value, true
}

func (em *ExpiringMap) Delete(key string) {
    em.m.Lock()
    defer em.m.Unlock()
    delete(em.items, key)
}

func (em *ExpiringMap) deleteExpiredKeys() {
    em.m.Lock()
    defer em.m.Unlock()
    now := time.Now().UnixNano()
    for key, item := range em.items {
        if now < item.expiration {
            break
        }
        delete(em.items, key)
    }
}

func (em *ExpiringMap) cleanup() {
    for {
        time.Sleep(em.timeout) // 阻塞协程
        em.deleteExpiredKeys()
    }
}

func main() {
    em := NewExpiringMap(time.Second * 10)

    time.Sleep(time.Second * 15)

    _, ok := em.Get("key1")
    if !ok {
        println("key1 is deleted")
    }

    _, ok = em.Get("key2")
    if !ok {
        println("key2 is deleted")
    }
}
如果你有魔法,你可以看到一个评论框~