Golang Go语言中使用mgo并发操作导致死锁
go 语言的 mongodb drive mgo 不是说线程安全的么?多个协成一并发一下就死锁了啊,有人用过这个么?
Golang Go语言中使用mgo并发操作导致死锁
https://gist.github.com/snower/06c165a8448076add35d2c6e42f2b877
差不多 count 计数到 4 万上下就没反应了
测试了你的代码,确实跑不顺畅,到后面是每 60 秒输出一条。不知道 60 秒是什么梗
我测试没有任何问题
就是这个问题,好奇怪啊,看了一天也没看出是什么问题…
一样的?要同时发起数万查询才会出这个问题,似乎
更新 1 :
加了-race 参数就能顺利跑完
go run -race test_mgo.go
更新 2 :
60 秒应该是 socket 超时,设置 session.SetSocketTimeout(35*time.Second) ,就会变成每 35 秒输出一条
感觉确实是 mgo 的问题,建议楼主去 github 提 issue
这个应该跟用的 mongodb 的配置有关,我这边反正一点问题都没有,顺利跑完, mongodb 是 ubuntu apt-get 装的 v2.6.10
ulimit -a 看看改过没有?
嗯,再测测看看
和这个没关系吧,整个只打开了一个链接…
可能是 setMode 造成的,只有 Monotonic 是 session 线程安全的,对没个 go 你试试用 session.Clone() Close()方法试试?
直接
for(){go foo()}
效率还是很低的,一方面是系统资源的申请还有 fd 的限制
第二就是资源回收。
建议用 chan 做队列和配合 select 效果应该很好
不要一直用一个 *mgo.Session ,尽量 Clone 新的 来用
少了两个关键之,密集申请和密集回收
用 go 起新的协程也需要占用 fd ,能详细解释一下么?
那么这样岂不要不断的关闭连接打开新连接了,如果有副本集的话,还有不断更新集群信息,这样效率太低了吧
mgo 的 Copy 是从连接池中取,不是重新创建的。
哦,是 clone ,看错 close 了,为什么要这么设计,好怪啊。。
昨晚试过在 for 循环里面 clone ,然后在 test()里面调 close ,结果还是不行
for i := 0; i < 100001; i++ {
go test(session.Clone(), i)
}
刚刚又试了一下把 clone 也放到 test()里面,就顺利跑完了。
看来 clone 需要在使用的 goroutine 里面调才有效
https://github.com/go-mgo/mgo/pull/572
居然这么久了这个问题还在,那么我来更新下解决方案吧。
在Golang中使用mgo(MongoDB官方Go驱动的早期版本)进行并发操作时遇到死锁问题,通常是由于mgo的session管理不当导致的。以下是一些可能的解决方案和建议:
-
Session管理:确保每个goroutine使用独立的session副本或通过session的
Copy
方法创建新的session。mgo的session不是线程安全的,因此在并发环境下,每个操作应该使用自己的session实例。 -
设置PoolSize:通过
mgo.SetPoolSize(n)
设置session池的最大大小,确保有足够的session可供并发操作使用。这有助于减少因session不足而导致的阻塞和潜在死锁。 -
使用Safe模式:在进行写操作时,确保使用
session.Safe()
或设置更高的写关注级别,这有助于在出现问题时捕获并处理错误,从而避免死锁。 -
升级驱动:如果可能,考虑升级到mgo的更新版本或切换到官方推荐的MongoDB Go驱动(如
go.mongodb.org/mongo-driver/mongo
),这些驱动可能包含对并发操作的更好支持。 -
调试和监控:使用Go的并发调试工具(如
race
检测器)和MongoDB的监控工具来诊断死锁原因。这些工具可以帮助你识别竞争条件和资源争用。
总之,处理mgo并发操作中的死锁问题通常需要仔细管理session生命周期、合理配置session池以及使用最新的驱动库。在设计和实现并发应用时,务必考虑这些最佳实践。