为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
皈依舞 2023-03-21 15:30:15
是否可以在不每次都创建新结构的情况下LoadOrStore进入围棋?sync.Map如果没有,有哪些替代方案可用?这里的用例是,如果我将 用作sync.Map缓存,其中缓存未命中很少见(但可能),并且在我想添加到地图的缓存未命中时,我需要在每次调用时初始化一个结构,而LoadOrStore不仅仅是在需要时创建结构。我担心这会伤害 GC,初始化数十万个不需要的结构。在 Java 中,这可以使用computeIfAbsent.
查看完整描述

3 回答

?
偶然的你

TA贡献1841条经验 获得超3个赞

你可以试试:


var m sync.Map

s, ok := m.Load("key")

if !ok {

    s, _ = m.LoadOrStore("key", "value")

}


fmt.Println(s)

播放演示


查看完整回答
反对 回复 2023-03-21
?
白衣非少年

TA贡献1155条经验 获得超0个赞

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


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

}


查看完整回答
反对 回复 2023-03-21
?
慕侠2389804

TA贡献1719条经验 获得超6个赞

包同步

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=. -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:


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


            }

        }

    }

}


查看完整回答
反对 回复 2023-03-21
  • 3 回答
  • 0 关注
  • 228 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号