Похоже, можно использовать вторую карту для ожидания, если извлечение уже выполняется.
type PostManager struct {
sync.Map
q sync.Map
}
func (pc *PostManager) Fetch(id int) Post {
post, ok := pc.Load(id)
if ok {
fmt.Printf("Using cached post %v\n", id)
return post.(Post)
}
fmt.Printf("Fetching post %v\n", id)
if c, loaded := pc.q.LoadOrStore(id, make(chan struct{})); !loaded {
post = pc.fetchPost(id)
pc.Store(id, post)
close(c.(chan struct{}))
} else {
<-c.(chan struct{})
post,_ = pc.Load(id)
}
return post.(Post)
}
Или, немного более сложно, с той же картой; -)
func (pc *PostManager) Fetch(id int) Post {
p, ok := pc.Load(id)
if !ok {
fmt.Printf("Fetching post %v\n", id)
if p, ok = pc.LoadOrStore(id, make(chan struct{})); !ok {
fetched = pc.fetchPost(id)
pc.Store(id, fetched)
close(p.(chan struct{}))
return fetched
}
}
if cached, ok := p.(Post); ok {
fmt.Printf("Using cached post %v\n", id)
return cached
}
fmt.Printf("Wating for cached post %v\n", id)
<-p.(chan struct{})
return pc.Fetch(id)
}