-
偶然的你
你可以试试:var m sync.Maps, ok := m.Load("key")if !ok { s, _ = m.LoadOrStore("key", "value")}fmt.Println(s)播放演示
-
白衣非少年
这是我的解决方案:使用 sync.Map 和 sync.Onetype syncData struct { data interface{} once *sync.Once}func LoadOrStore(m *sync.Map, key string, f func() (interface{}, error)) (interface{}, error) { temp, _ := m.LoadOrStore(key, &syncData{ data: nil, once: &sync.Once{}, }) d := temp.(*syncData) var err error if d.data == nil { d.once.Do(func() { d.data, err = f() if err != nil { //if failed, will try again by new sync.Once d.once = &sync.Once{} } }) } return d.data, err}
-
慕侠2389804
包同步import "sync"类型地图Map 就像 Go 的 map[interface{}]interface{} 但对于多个 goroutines 的并发使用是安全的,无需额外的锁定或协调。加载、存储和删除以摊销的常数时间运行。Map 类型是专门的。大多数代码应该使用普通的 Go 地图,使用单独的锁定或协调,以获得更好的类型安全性,并且更容易维护其他不变量以及地图内容。Map 类型针对两种常见用例进行了优化:(1) 当给定键的条目只写入一次但读取多次时,如在只会增长的缓存中,或 (2) 当多个 goroutine 读取、写入和读取时覆盖不相交的键集的条目。在这两种情况下,与 Go map 与单独的 Mutex 或 RWMutex 配对相比,使用 Map 可以显着减少锁争用。解决这些问题的通常方法是构建一个使用模型,然后对其进行基准测试。例如,因为“高速缓存未命中是罕见的”,假设Loadwiil 大部分时间都可以工作,并且只LoadOrStore在必要时(通过值分配和初始化)工作。$ go test map_test.go -bench=. -benchmemBenchmarkHit-4 2 898810447 ns/op 44536 B/op 1198 allocs/opBenchmarkMiss-4 1 2958103053 ns/op 483957168 B/op 43713042 allocs/op$map_test.go:package mainimport ( "strconv" "sync" "testing")func BenchmarkHit(b *testing.B) { for N := 0; N < b.N; N++ { var m sync.Map for i := 0; i < 64*1024; i++ { for k := 0; k < 256; k++ { // Assume cache hit v, ok := m.Load(k) if !ok { // allocate and initialize value v = strconv.Itoa(k) a, loaded := m.LoadOrStore(k, v) if loaded { v = a } } _ = v } } }}func BenchmarkMiss(b *testing.B) { for N := 0; N < b.N; N++ { var m sync.Map for i := 0; i < 64*1024; i++ { for k := 0; k < 256; k++ { // Assume cache miss // allocate and initialize value var v interface{} = strconv.Itoa(k) a, loaded := m.LoadOrStore(k, v) if loaded { v = a } _ = v } } }}