英文:
Golang manipulating object inside a sync.Map
问题
我正在尝试操作一个包含sync.Map的sync.Map的golang代码,但是在类型转换方面遇到了一些问题。
我有以下代码:
func (cluster *Cluster) action(object1, object2 MyObject) {
value, _ := cluster.globalMap.LoadOrStore(object1.name, sync.Map{})
localMap := value.(sync.Map)
localMap.Store(object2.Name, object2)
value2, _ := cluster.resourceInflight.Load(node.Name)
forComparison := value2.(sync.Map)
fmt.Println(localMap.Load(object2.Name))
fmt.Println(forComparison.Load(object2.Name))
}
{myObject map[] map[]} true
<nil> false
我这样做是因为我希望保持localMap的线程安全性。
问题是,我期望我的两个打印结果相同,因为"forComparison"应该指向与"localMap"相同的对象。但是第二个结果是nil。
我怀疑问题出在将接口"value"转换为实际的"sync.Map"时。但我不确定如何在内联转换的情况下调用.Store方法。
我考虑过将localMap存储在cluster.globalMap中,但我觉得这样做是不正确的,因为它会破坏使用localSyncMap的整个目的,并且会创建并发问题。
对于我应该怎么做,你有什么建议吗?
英文:
I am trying to manipulate a golang sync.Map of sync.Map, but I have some issues with the casting.
I have the following code:
func (cluster *Cluster) action(object1, object2 MyObject) {
value, _ := cluster.globalMap.LoadOrStore(object1.name, sync.Map{})
localMap := value.(sync.Map)
localMap.Store(object2.Name, object2)
value2, _ := cluster.resourceInflight.Load(node.Name)
forComparison := value2.(sync.Map)
fmt.Println(localMap.Load(object2.Name))
fmt.Println(forComparison.Load(object2.Name))
}
{myObject map[] map[]} true
<nil> false
I am doing this since I wish to keep the content of localMap thread safe.
The problem is I am expecting to have the same result for my two print, as "forComparison" should be pointing to the same object than "localMap". But second result is nil.
I am suspecting that the problem is coming from the casting of the interface "value" into an actual "sync.Map". But I am not sure how I can actually call the .Store method with inline casting.
I thought about Storing localMap inside cluster.globalMap, but this seems incorrect to me as it would break the whole point of using a localSyncMap and create concurrency issues.
Any input on what I should do ?
答案1
得分: 2
根据评论所述,问题在于你复制了一个sync.Map
。以下代码将失败(输出"Not found" - playground):
var sm sync.Map
var x interface{}
x = sm
sm2 := x.(sync.Map)
sm2.Store("test", "test")
result, ok := sm.Load("test")
if ok {
fmt.Printf("Found: %s\n", result)
} else {
fmt.Printf("Not found\n")
}
而使用指针则能按预期工作:
var sm sync.Map
var x interface{}
x = &sm
sm2 := x.(*sync.Map)
sm2.Store("test", "test")
result, ok := sm.Load("test")
if ok {
fmt.Printf("Found: %s\n", result)
} else {
fmt.Printf("Not found\n")
}
运行go vet
可能会警告你其他问题(sync.Map
包含一个sync.Mutex
,这些"在首次使用后不能复制")。
请注意,Sync.Map的文档中指出:
Map类型是专用的。大多数代码应该使用普通的Go map,通过单独的锁定或协调来提供更好的类型安全性,并使维护与地图内容一起的其他不变量更容易。
英文:
As per the comments the issue was that you were copying a sync.Map
; the following code will fail (output "Not found" - playground):
var sm sync.Map
var x interface{}
x = sm
sm2 := x.(sync.Map)
sm2.Store("test", "test")
result, ok := sm.Load("test")
if ok {
fmt.Printf("Found: %s\n", result)
} else {
fmt.Printf("Not found\n")
}
Whereas using a pointer works as expected:
var sm sync.Map
var x interface{}
x = &sm
sm2 := x.(*sync.Map)
sm2.Store("test", "test")
result, ok := sm.Load("test")
if ok {
fmt.Printf("Found: %s\n", result)
} else {
fmt.Printf("Not found\n")
}
Running go vet
would probably have warned you about other issues (sync.Map
contains a sync.Mutex
and these "must not be copied after first use").
Note that the docs for Sync.Map state:
>The Map type is specialized. Most code should use a plain Go map instead, with separate locking or coordination, for better type safety and to make it easier to maintain other invariants along with the map content.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论