mongodb - Golang MGO 模块是否锁定或解锁 Go 对象?
问题描述
我试图了解 Mongo 是否锁定 Go 对象。
第一个函数适用于 json 编码器,但是第二个函数失败fatal error: sync: Unlock of unlocked RWMutex
。这是因为 mongo.Find 已经在尝试锁定/解锁状态对象吗?我需要在外部处理我的围棋对象的比赛还是由 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 字段替换为字符串映射即可。
解决方案
首先, drop gopkg.in/mgo.v2
,它已经过时,没有维护。而是使用社区支持的 fork: github.com/globalsign/mgo
。
接下来,您应该首先阅读公共的、打包的文档,如果文档没有提供答案,则仅“恢复”阅读源代码以清除此类内容。但是从源头得出结论总是很危险的,因为实施可能随时发生变化,只有记录在案的内容才能得到保证。状态文件mgo.Session
:
所有 Session 方法都是并发安全的,可以从多个 goroutine 调用。
这是您拥有的所有保证,也是您应该依赖的所有保证。使用 of 的方法mgo.Collection
对于并发使用可能安全,也可能不安全,所以不要那样做。需要时,始终从会话中获取“新”集合,因为可以安全地从多个 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
为零值的字段,这是一个未锁定的互斥体。而一旦发生这种情况,后续的解锁显然会失败(恐慌)。
解决方案?将锁移到您打算序列化/反序列化的结构值之外。或者至少不要期望锁定状态会与其他字段一起转移。
推荐阅读
- powerbi - 如何平均一列值,同时排除另一列中包含某个值的行?PowerBi
- leaflet - Leaflet Routing Machine 上的语言未切换为法语
- python - 如何在 jupyter 笔记本(VSCode + Python 扩展)中隐藏单元格输出?
- javascript - 当 Share Point 2013 列表中的列为空时,如何隐藏 Null 文本?
- spring-boot - 在 spring-boot 2.1.9.release 中寻找匹配的 CachePublicMetrics
- typescript - 如何为这样的函数定义类型?
- rest - 使用可选值创建两个不同的 rest api
- java - 来自 Spring RestClient 和 Jackson 的嵌套 JSON 对象
- twilio - 如何根据用户的回答提出不同的问题?
- generics - 将对象实例化并添加到通用扩展方法