Golang MGO 模块是否锁定或解锁 Go 对象?
Does the Golang MGO module lock or unlock Go objects?
我想了解 Mongo 是否锁定了 Go 对象。
第一个函数在 json 编码器上运行良好,但第二个函数失败 fatal error: sync: Unlock of unlocked RWMutex
。这是因为 mongo.Find 已经在尝试 lock/unlock 状态对象了吗?我是否需要在外部处理我的围棋对象的比赛或 MGO 会处理它?我尝试阅读源代码,但我无法得出结论。
任何人将不胜感激!
import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"io"
"sync"
"encoding/json"
)
type ApplicationState struct {
FileStates map[string]FileState `json:"fileStates" bson:"fileStates"`
lock sync.RWMutex `json:"-" bson:"-"`
}
func (state *ApplicationState) ReadState(reader io.Reader) error {
state.lock.Lock()
defer state.lock.Unlock()
return json.NewDecoder(reader).Decode(state)}
func (state *ApplicationState) ReadStateMGO(c *mgo.Collection) error {
state.lock.Lock()
defer state.lock.Unlock()
return c.Find( bson.M{} ).Select( bson.M{"_id": 0} ).One(state)}
注意:要对其进行测试,您只需将 Filestate 字段替换为字符串映射即可。
首先,删除 gopkg.in/mgo.v2
,它已过时,无人维护。而是使用社区支持的分支:github.com/globalsign/mgo
.
接下来,您应该先阅读 public 软件包文档,如果文档没有提供答案,则只 "revert" 阅读源代码以清除这些问题。但从源头上得出结论总是很危险的,因为实施可能随时发生变化,只有记录在案的才能得到保证。 mgo.Session
的文档说明:
All Session methods are concurrency-safe and may be called from multiple goroutines.
这就是你的全部保障,也是你该依赖的。使用 mgo.Collection
的方法对于并发使用可能安全也可能不安全,所以不要那样做。需要时,始终从会话中获取 "new" 集合,因为可以安全地从多个 goroutine 访问它。
现在谈谈你的实际问题。
您的 ApplicationState
结构类型包含一个锁 (sync.RWMutex
),并且您将查询结果解组为持有该锁的相同 ApplicationState
值:
func (state *ApplicationState) ReadStateMGO(c *mgo.Collection) error {
state.lock.Lock()
defer state.lock.Unlock()
return c.Find( bson.M{} ).Select( bson.M{"_id": 0} ).One(state)
}
这是一个危险信号!不要这样做!解组为一个值可能会清除任何字段,包括锁!
是的,你可能会说它是一个未导出的字段,所以 mgo
包不应该/不能改变它。这是真的,但是 mgo
包可能会决定创建一个新的 ApplicationState
值来解组,并且新值可能会分配给传递的指针指向的值 (state
) .
如果发生这种情况,新创建的 ApplicationState
将有一个 lock
字段作为其零值,这是一个未锁定的互斥量。而一旦出现这种情况,后续的解锁显然会失败(panic)。
解决方案?将锁移到您打算序列化/反序列化的结构值之外。或者至少不要期望锁定状态与其他字段一起转移。
我想了解 Mongo 是否锁定了 Go 对象。
第一个函数在 json 编码器上运行良好,但第二个函数失败 fatal error: sync: Unlock of unlocked RWMutex
。这是因为 mongo.Find 已经在尝试 lock/unlock 状态对象了吗?我是否需要在外部处理我的围棋对象的比赛或 MGO 会处理它?我尝试阅读源代码,但我无法得出结论。
任何人将不胜感激!
import (
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"io"
"sync"
"encoding/json"
)
type ApplicationState struct {
FileStates map[string]FileState `json:"fileStates" bson:"fileStates"`
lock sync.RWMutex `json:"-" bson:"-"`
}
func (state *ApplicationState) ReadState(reader io.Reader) error {
state.lock.Lock()
defer state.lock.Unlock()
return json.NewDecoder(reader).Decode(state)}
func (state *ApplicationState) ReadStateMGO(c *mgo.Collection) error {
state.lock.Lock()
defer state.lock.Unlock()
return c.Find( bson.M{} ).Select( bson.M{"_id": 0} ).One(state)}
注意:要对其进行测试,您只需将 Filestate 字段替换为字符串映射即可。
首先,删除 gopkg.in/mgo.v2
,它已过时,无人维护。而是使用社区支持的分支:github.com/globalsign/mgo
.
接下来,您应该先阅读 public 软件包文档,如果文档没有提供答案,则只 "revert" 阅读源代码以清除这些问题。但从源头上得出结论总是很危险的,因为实施可能随时发生变化,只有记录在案的才能得到保证。 mgo.Session
的文档说明:
All Session methods are concurrency-safe and may be called from multiple goroutines.
这就是你的全部保障,也是你该依赖的。使用 mgo.Collection
的方法对于并发使用可能安全也可能不安全,所以不要那样做。需要时,始终从会话中获取 "new" 集合,因为可以安全地从多个 goroutine 访问它。
现在谈谈你的实际问题。
您的 ApplicationState
结构类型包含一个锁 (sync.RWMutex
),并且您将查询结果解组为持有该锁的相同 ApplicationState
值:
func (state *ApplicationState) ReadStateMGO(c *mgo.Collection) error {
state.lock.Lock()
defer state.lock.Unlock()
return c.Find( bson.M{} ).Select( bson.M{"_id": 0} ).One(state)
}
这是一个危险信号!不要这样做!解组为一个值可能会清除任何字段,包括锁!
是的,你可能会说它是一个未导出的字段,所以 mgo
包不应该/不能改变它。这是真的,但是 mgo
包可能会决定创建一个新的 ApplicationState
值来解组,并且新值可能会分配给传递的指针指向的值 (state
) .
如果发生这种情况,新创建的 ApplicationState
将有一个 lock
字段作为其零值,这是一个未锁定的互斥量。而一旦出现这种情况,后续的解锁显然会失败(panic)。
解决方案?将锁移到您打算序列化/反序列化的结构值之外。或者至少不要期望锁定状态与其他字段一起转移。