在 sync.Map 中加载或存储而无需每次都创建新结构

是否可以在不每次都创建新结构的情况下LoadOrStore进入围棋?sync.Map如果没有,有哪些替代方案可用?

这里的用例是,如果我将 用作sync.Map缓存,其中缓存未命中很少见(但可能),并且在我想添加到地图的缓存未命中时,我需要在每次调用时初始化一个结构,而LoadOrStore不仅仅是在需要时创建结构。我担心这会伤害 GC,初始化数十万个不需要的结构。

在 Java 中,这可以使用computeIfAbsent.



皈依舞
浏览 229回答 3
3回答

偶然的你

你可以试试: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&nbsp;"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&nbsp; &nbsp; &nbsp;2&nbsp; &nbsp; &nbsp;898810447 ns/op&nbsp; &nbsp; &nbsp; &nbsp; 44536 B/op&nbsp; &nbsp; &nbsp; &nbsp; 1198 allocs/opBenchmarkMiss-4&nbsp; &nbsp; 1&nbsp; &nbsp; 2958103053 ns/op&nbsp; &nbsp; 483957168 B/op&nbsp; &nbsp; 43713042 allocs/op$map_test.go:package mainimport (&nbsp; &nbsp; "strconv"&nbsp; &nbsp; "sync"&nbsp; &nbsp; "testing")func BenchmarkHit(b *testing.B) {&nbsp; &nbsp; for N := 0; N < b.N; N++ {&nbsp; &nbsp; &nbsp; &nbsp; var m sync.Map&nbsp; &nbsp; &nbsp; &nbsp; for i := 0; i < 64*1024; i++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for k := 0; k < 256; k++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Assume cache hit&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v, ok := m.Load(k)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if !ok {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // allocate and initialize value&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v = strconv.Itoa(k)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a, loaded := m.LoadOrStore(k, v)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if loaded {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v = a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _ = v&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}func BenchmarkMiss(b *testing.B) {&nbsp; &nbsp; for N := 0; N < b.N; N++ {&nbsp; &nbsp; &nbsp; &nbsp; var m sync.Map&nbsp; &nbsp; &nbsp; &nbsp; for i := 0; i < 64*1024; i++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for k := 0; k < 256; k++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Assume cache miss&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // allocate and initialize value&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var v interface{} = strconv.Itoa(k)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a, loaded := m.LoadOrStore(k, v)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if loaded {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; v = a&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _ = v&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go