Reputation: 784
This example seems to fetch data once, but I don't think it will invoke a fetchDataInBackground
function in background for each key
concurrently.
func Get(key string){
...
if itIsTheTimeToRefreshData{
var once sync.Once
onceBody := func() {
fetchDataInBackground()
}
go func() {
once.Do(onceBody)
}()
}
...
}
what I need to do is to assign each Once
instance to a key
so that all fetch data for different keys can be done concurrently.
how do I do that?
Upvotes: 1
Views: 2705
Reputation: 973
I think sync.Once
is not well for such task. You need to maintain some flag ("once") for each key individually. Map with mutexed access is one of possible solutions.
Full working example:
package main
import (
"fmt"
"sync"
"time"
)
var once map[string]bool
var onceMutex sync.Mutex
var itIsTheTimeToRefreshData = true
func Get(key string) {
fmt.Printf("Access for key: %s\n", key)
if itIsTheTimeToRefreshData {
onceBody := func() {
fmt.Printf("Only once for key: %s\n", key)
//fetchDataInBackground()
}
onceMutex.Lock()
if !once[key] { // is it first time?
once[key] = true
onceMutex.Unlock()
// refresh something here
go onceBody()
} else {
onceMutex.Unlock()
}
}
}
func main() {
once = make(map[string]bool)
// do it first time in parallel
for i := 0; i < 10; i++ {
key := fmt.Sprintf("i%d", i)
go func(key string) {
Get(key)
}(key)
}
// and another time
for i := 0; i < 10; i++ {
key := fmt.Sprintf("i%d", i)
go func(key string) {
Get(key)
}(key)
}
fmt.Println("All requested.")
time.Sleep(1 * time.Second)
}
Upvotes: 4