3 回答

TA貢獻(xiàn)1155條經(jīng)驗 獲得超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
}

TA貢獻(xiàn)1719條經(jīng)驗 獲得超6個贊
import "sync"
Map 就像 Go 的 map[interface{}]interface{} 但對于多個 goroutines 的并發(fā)使用是安全的,無需額外的鎖定或協(xié)調(diào)。加載、存儲和刪除以攤銷的常數(shù)時間運行。
Map 類型是專門的。大多數(shù)代碼應(yīng)該使用普通的 Go 地圖,使用單獨的鎖定或協(xié)調(diào),以獲得更好的類型安全性,并且更容易維護其他不變量以及地圖內(nèi)容。
Map 類型針對兩種常見用例進行了優(yōu)化:(1) 當(dāng)給定鍵的條目只寫入一次但讀取多次時,如在只會增長的緩存中,或 (2) 當(dāng)多個 goroutine 讀取、寫入和讀取時覆蓋不相交的鍵集的條目。在這兩種情況下,與 Go map 與單獨的 Mutex 或 RWMutex 配對相比,使用 Map 可以顯著減少鎖爭用。
解決這些問題的通常方法是構(gòu)建一個使用模型,然后對其進行基準(zhǔn)測試。
例如,因為“高速緩存未命中是罕見的”,假設(shè)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
}
}
}
}
- 3 回答
- 0 關(guān)注
- 205 瀏覽
添加回答
舉報