私は、(可能な限り多くの)マップエントリを範囲指定してチャネルに送信する必要があるシナリオを持っています。チャネルのもう一方の端での操作には長い時間がかかり、マップは同時にアクセスされます(RWMutex
によって保護されます)。地図はかなり大きく、私はそれの一時的なコピーを作成しないようにしたい。マップエントリを同時にチャネルに読み込みます
は、私はこのような構造体があるとします。
type Example struct {
sync.RWMutex
m map[string]struct{}
}
は今、私はこのような何かを思い付いた:
func (e *Example) StreamAll() <-chan string {
toReturn := make(chan string)
go func() {
e.RLock()
defer e.RUnlock()
for k := range e.m {
e.RUnlock()
toReturn <- k
e.RLock()
}
close(toReturn)
}()
return toReturn
}
language specificationは、マップ上までについてのこの興味深いビットを持っています
まだ到達していないマップエントリが反復処理中に削除された場合、対応する反復値は削除されません生産される。反復中にマップエントリが作成された場合、そのエントリは反復中に生成されるか、スキップされる可能性があります。
ここで私が知りたいのは、マップ間の距離が変更されても、マップ上の範囲指定方法が機能するという保証はありますか?最後に読み込んだキーが削除された場合も含めて削除されますか?私はすべての地図の項目が必要なわけではありませんが、ほとんどは地図の項目です。あなたが鍵を生成するとしてあなたのマップが変更され、あなたが得るよう:これはあなたが持っているものである
0)一貫性のないスナップショット:
package main
import (
"fmt"
"sync"
)
type Example struct {
sync.RWMutex
m map[string]struct{}
}
func NewExample() *Example {
return &Example{
m: make(map[string]struct{}),
}
}
func (e *Example) Put(s string) {
e.Lock()
defer e.Unlock()
e.m[s] = struct{}{}
}
func (e *Example) Delete(s string) {
e.Lock()
defer e.Unlock()
delete(e.m, s)
}
func (e *Example) StreamAll() <-chan string {
toReturn := make(chan string)
go func() {
e.RLock()
defer e.RUnlock()
for k := range e.m {
e.RUnlock()
toReturn <- k
e.RLock()
}
close(toReturn)
}()
return toReturn
}
func main() {
e := NewExample()
e.Put("a")
e.Put("b")
values := e.StreamAll()
// Assume other goroutines concurrently call Put and Delete on e
for k := range values {
fmt.Println(k)
}
}
あなたのプレイグランドへのリンクは動作していません。 – OneOfOne
ありがとう、私は今質問にそれを引っ張った。 – mrd0ll4r
'range'アクション自体は並行安全な方法で実行する必要があります。マップが変更されている場合は、要素の奇妙なシーケンスが得られる可能性があります(マップ上を移動するたびに、 –