首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >每次在没有创建新结构的情况下在LoadOrStore中使用sync.Map

每次在没有创建新结构的情况下在LoadOrStore中使用sync.Map
EN

Stack Overflow用户
提问于 2018-08-16 20:46:52
回答 3查看 3.1K关注 0票数 3

是否有可能在每次不创建新结构的情况下将LoadOrStore转换为Go sync.Map?如果没有,还有什么可供选择的?

这里的用例是,如果我使用sync.Map作为缓存,其中缓存丢失很少(但可能),并且在我想要添加到映射中的缓存丢失时,我需要在每次调用LoadOrStore时初始化一个结构,而不仅仅是在需要时创建结构。我担心这会损害GC,初始化成千上万个不需要的结构。

在Java中,这可以使用computeIfAbsent来完成。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-08-16 22:47:44

包同步 导入“同步” 类型图 Map类似于Go映射接口{}接口{},但是对于多个goroutines并发使用是安全的,而不需要额外的锁定或协调。加载、存储和删除在摊销的恒定时间内运行。 Map类型是专门化的。大多数代码应该使用普通的Go映射,使用单独的锁定或协调,以获得更好的类型安全性,并使维护其他不变量和映射内容变得更容易。 Map类型是针对两种常见的用例进行优化的:(1)当给定键的条目只写一次但多次读取时,就像在只增长的缓存中那样,或者(2)当多个goroutines对不相交的键集进行读、写和覆盖条目时。在这两种情况下,与单独的Mutex或RWMutex配对的Go映射相比,使用Map可以显著减少锁争用。

解决这些问题的通常方法是构建一个使用模型,然后对其进行基准测试。

例如,由于“缓存丢失很少见”,因此假设Load大部分时间都能工作,并且在必要时只使用LoadOrStore (包括值分配和初始化)。

代码语言:javascript
复制
$ go test map_test.go -bench=. -benchmem
BenchmarkHit-4     2     898810447 ns/op        44536 B/op        1198 allocs/op
BenchmarkMiss-4    1    2958103053 ns/op    483957168 B/op    43713042 allocs/op
$

map_test.go

代码语言:javascript
复制
package main

import (
    "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

            }
        }
    }
}
票数 0
EN

Stack Overflow用户

发布于 2019-09-12 08:34:59

你可以试试:

代码语言:javascript
复制
var m sync.Map
s, ok := m.Load("key")
if !ok {
    s, _ = m.LoadOrStore("key", "value")
}

fmt.Println(s)

播放演示

票数 0
EN

Stack Overflow用户

发布于 2021-08-27 13:37:48

这是我的解决方案:使用sync.Map和sync.One

代码语言:javascript
复制
type 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
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51885117

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档