V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
sujin190

go 用 mgo 并发操作死锁

  •  
  •   sujin190 ·
    snower · Jan 10, 2017 · 2925 views
    This topic created in 3408 days ago, the information mentioned may be changed or developed.
    go 语言的 mongodb drive mgo 不是说线程安全的么?多个协成一并发一下就死锁了啊,有人用过这个么?
    Supplement 1  ·  Mar 13, 2021
    https://github.com/go-mgo/mgo/pull/572

    居然这么久了这个问题还在,那么我来更新下解决方案吧。
    22 replies    2021-03-13 11:35:35 +08:00
    heimonsy
        1
    heimonsy  
       Jan 10, 2017
    上代码
    sujin190
        2
    sujin190  
    OP
       Jan 10, 2017
    @heimonsy https://gist.github.com/snower/06c165a8448076add35d2c6e42f2b877
    差不多 count 计数到 4 万上下就没反应了
    zjx20
        3
    zjx20  
       Jan 10, 2017
    @sujin190 测试了你的代码,确实跑不顺畅,到后面是每 60 秒输出一条。不知道 60 秒是什么梗
    heimonsy
        4
    heimonsy  
       Jan 10, 2017
    我测试没有任何问题
    sujin190
        5
    sujin190  
    OP
       Jan 10, 2017
    @zjx20 就是这个问题,好奇怪啊,看了一天也没看出是什么问题..
    sujin190
        6
    sujin190  
    OP
       Jan 10, 2017
    @heimonsy 一样的?要同时发起数万查询才会出这个问题,似乎
    zjx20
        7
    zjx20  
       Jan 10, 2017
    更新 1 :
    加了-race 参数就能顺利跑完
    go run -race test_mgo.go

    更新 2 :
    60 秒应该是 socket 超时,设置 session.SetSocketTimeout(35*time.Second) ,就会变成每 35 秒输出一条

    感觉确实是 mgo 的问题,建议楼主去 github 提 issue
    heimonsy
        8
    heimonsy  
       Jan 10, 2017
    这个应该跟用的 mongodb 的配置有关,我这边反正一点问题都没有,顺利跑完, mongodb 是 ubuntu apt-get 装的 v2.6.10
    janxin
        9
    janxin  
       Jan 10, 2017
    ulimit -a 看看改过没有?
    sujin190
        10
    sujin190  
    OP
       Jan 11, 2017
    @zjx20 嗯,再测测看看
    sujin190
        11
    sujin190  
    OP
       Jan 11, 2017
    @janxin 和这个没关系吧,整个只打开了一个链接..
    mengskysama
        12
    mengskysama  
       Jan 11, 2017   ❤️ 1
    可能是 setMode 造成的,只有 Monotonic 是 session 线程安全的,对没个 go 你试试用 session.Clone() Close()方法试试?
    struCoder
        13
    struCoder  
       Jan 11, 2017
    直接
    for(){go foo()}
    效率还是很低的,一方面是系统资源的申请还有 fd 的限制
    第二就是资源回收。

    建议用 chan 做队列和配合 select 效果应该很好
    fuxiaohei
        14
    fuxiaohei  
       Jan 11, 2017   ❤️ 1
    不要一直用一个 *mgo.Session ,尽量 Clone 新的 来用
    struCoder
        15
    struCoder  
       Jan 11, 2017
    @struCoder 少了两个关键之,密集申请和密集回收
    sujin190
        16
    sujin190  
    OP
       Jan 11, 2017
    @struCoder 用 go 起新的协程也需要占用 fd ,能详细解释一下么?
    sujin190
        17
    sujin190  
    OP
       Jan 11, 2017
    @fuxiaohei 那么这样岂不要不断的关闭连接打开新连接了,如果有副本集的话,还有不断更新集群信息,这样效率太低了吧
    janxin
        18
    janxin  
       Jan 11, 2017
    @sujin190 mgo 的 Copy 是从连接池中取,不是重新创建的。
    sujin190
        19
    sujin190  
    OP
       Jan 11, 2017
    @janxin 哦,是 clone ,看错 close 了,为什么要这么设计,好怪啊。。
    zjx20
        20
    zjx20  
       Jan 11, 2017
    昨晚试过在 for 循环里面 clone ,然后在 test()里面调 close ,结果还是不行
    for i := 0; i < 100001; i++ {
    go test(session.Clone(), i)
    }

    刚刚又试了一下把 clone 也放到 test()里面,就顺利跑完了。
    看来 clone 需要在使用的 goroutine 里面调才有效
    njutree
        21
    njutree  
       Jan 11, 2017
    根据我的理解这个不是死锁,是卡住了。 mgo.Session 会起一个协程运行 readLoop() 读取数据,这里面会有很多锁,也就是当你开的协程少(具体看机器配置)时是没有什么问题的。 一旦你把协程数提高比如你代码里面的 10w 时, readLoop() 协程能分配到的计算资源有限,所以就会出现卡住或缓慢得到查询请求的情况。 你可以把协程数降低,单个协程的查询数提高,查询速度就会变快。 同理 copy 多个 mgo.Session 就会有启多个 readLoop() 协程 ,每个查询在对应的 readLoop ,执行回调就不会卡住了。
    sujin190
        22
    sujin190  
    OP
       Mar 13, 2021
    https://github.com/go-mgo/mgo/pull/572

    居然这么久了这个问题还在,那么我来更新下解决方案吧。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   5740 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 83ms · UTC 06:50 · PVG 14:50 · LAX 23:50 · JFK 02:50
    ♥ Do have faith in what you're doing.