requirement:
实现阻塞读且并发安全的map
GO⾥⾯MAP如何实现key不存在 get操作等待 直到key存在或者超时,保证并发安全
implementation:
package main import ( "fmt" "sync" "time" ) type sp interface { Out(key string, val interface{}) Rd(key string, timeout time.Duration) interface{} } type Synmap struct { M map[string]*Entry rwm *sync.RWMutex } type Entry struct { ch chan interface{} value interface{} isExist bool } // initSynmap func NewSynmap() *Synmap { return &Synmap{ M: make(map[string]*Entry), rwm: &sync.RWMutex{}, } } // save func (m *Synmap) Out(key string, val interface{}) { m.rwm.Lock() defer m.rwm.Unlock() item, ok := m.M[key] if !ok { item = &Entry{ value: val, isExist: true, } m.M[key] = item return } if !item.isExist { // Rd goroutine is waiting if item.ch != nil { // Rd goroutine is stil not timeout item.ch <- val item.value = val item.isExist = true } } else { // just change the value item.value = val } return } // read func (m *Synmap) Rd(key string, timeout time.Duration) interface{} { timer := time.NewTimer(timeout) m.rwm.RLock() v, ok := m.M[key] m.rwm.RUnlock() if ok { return v.value } m.rwm.Lock() v = &Entry{ ch: make(chan interface{}), } m.M[key] = v m.rwm.Unlock() for { select { case result := <-v.ch: close(v.ch) fmt.Println("after waiting....") return result case <-timer.C: fmt.Println("timeout") close(v.ch) v.ch = nil return nil } } } func main() { synmap := NewSynmap() var wg sync.WaitGroup wg.Add(2) go func() { defer wg.Done() fmt.Println("try to read key = 123...") fmt.Println(synmap.Rd("123", 1*time.Second)) }() go func() { defer wg.Done() fmt.Println("start to write key") time.Sleep(2 * time.Second) synmap.Out("123", "outtttt") }() wg.Wait() }