Обычный map не гарантирует порядок. Варианты:
- можно сделать ordered map, но с этим окуратнее, куча подводных камней
- можно хранить в элементах время и либо ходить по нему через range удаляя все устаревшие элементы либо делать проверку при доступе к данным, если данные устарели - удаляем.
Можно сделать чуть проще:
- делаем ch := make(chan string, 100000)
- далее время от времени смотрим len(ch) и если он выше ну скажем половины от того что туда может влезть (подберите имперически исходя из количества и скорости пополнения данными или высчитывайте гибко) и удаляете тот элемент что первым читается из ch
https://play.golang.org/p/sopEgcwRZCpackage main
import (
"fmt"
"sync"
)
type Map struct {
sync.RWMutex
ch chan string
d map[string]string
}
func NewMap() (m *Map) {
m = new(Map)
m.ch = make(chan string, 10000)
m.d = make(map[string]string)
return
}
func (m *Map) Add(key, value string) {
m.Lock()
defer m.Unlock()
m.check(50, true)
m.d[key] = value
m.ch <- key
}
func (m *Map) Get(key string) string {
m.RLock()
defer m.RUnlock()
if v, ok := m.d[key]; ok {
return v
}
return ""
}
func (m *Map) Check() {
m.check(50, false)
}
func (m *Map) check(len_max int, is_lock bool) {
ch_len := len(m.ch)
if ch_len > len_max {
if !is_lock {
m.Lock()
defer m.Unlock()
}
ch_len = len(m.ch)
for i := 0; i < ch_len - len_max; i++ {
delete(m.d, <- m.ch)
}
}
}
func (m *Map) Len() int {
return len(m.ch)
}
func main() {
m := NewMap()
for i := 0; i < 1000; i++ {
m.Add(fmt.Sprintf("key_%s", i), fmt.Sprintf("value_%s", i))
}
fmt.Println(m.Len())
}
- храним не более len_max элементов+1 в map, при этом удаляем сначала самые старые в порядке их добавления
- есть проблема - если ключ был добавлен несколько раз то программа не видит что элемент обновился и всё равно его удалит как старый
- что бы этого не происходило нужно добавлять дату в ключь и проверять, если ключ имеет другую дату (или вместо даты инкрементный счётчик) то такой элемент пропускается (мы знаем что он уже где-то есть дальше в m.ch)