我遇到一种我无法理解的情况。在我的代码中,我使用函数需要读取一个映射(但不能写入,仅循环遍历此映射中现有数据的快照)。有我的代码:
type MyStruct struct {
*sync.RWMutex
MyMap map[int]MyDatas
}
var MapVar = MyStruct{ &sync.RWMutex{}, make(map[int]MyDatas) }
func MyFunc() {
MapVar.Lock()
MapSnapshot := MapVar.MyMap
MapVar.Unlock()
for _, a := range MapSnapshot { // Map concurrent write/read occur here
//Some stuff
}
}
main() {
go MyFunc()
}
函数“ MyFunc”在go例程中运行,只有一次,此功能没有多次运行。许多其他功能使用相同的方法访问相同的“ MapVar”,并且随机产生“映射并发写入/读取”。我希望有人能向我解释为什么我的代码是错误的。
谢谢您的时间。
edit:为澄清起见,我只是问为什么我的范围MapSnapshot会产生并发的地图写/读。由于无法使用同步互斥锁将真正的全局变量(MapVar)保存在本地变量(MapSnapshot)中,因此我无法理解如何同时使用此地图。
编辑:已解决。要在不使用相同引用的情况下将映射的内容复制到新变量中(从而避免映射并发读/写),我必须遍历它,并使用for循环将每个索引和内容写入新映射。
感谢xpare和nilsocket。
答案 0 :(得分:0)
此功能没有多次运行。许多其他函数使用相同的方法访问相同的“ MapVar”,并随机产生“地图并发写入/读取”
当您将MapVar.MyMap
的值传递给MapSnapshot
时,Map concurrent write/read
将永远不会出现,因为操作是用互斥量包装的。
但是在循环中,由于实际上在循环中进行读取过程,因此可能会发生错误。因此最好也用互斥体包装循环。
MapVar.Lock() // lock begin
MapSnapshot := MapVar.MyMap
for _, a := range MapSnapshot {
// Map concurrent write/read occur here
// Some stuff
}
MapVar.Unlock() // lock end
以下是我对您的论点的答复:
这个for循环要花很多时间,这个循环中有很多东西,所以锁定会降低其他例程的速度
根据您的声明The function "MyFunc" is run in a go routine, only once, there is no multiple runs of this func
,那么我认为让MyFunc
作为goroutine执行不是一个好选择。
为提高性能,最好使循环内的过程在goroutine中执行。
func MyFunc() {
for _, a := range MapVar.MyMap {
go func(a MyDatas) {
// do stuff here
}(a)
}
}
main() {
MyFunc() // remove the go keyword
}
如果您确实要复制 MapVar.MyMap
到另一个对象中,将其传递到另一个变量将无法解决(map
与{{1} },int
或其他原始类型。
请参考该线程How to copy a map?