用于寻路的mgo优化

时间:2015-10-15 11:04:33

标签: go mgo

我在Go中实现了一个A *算法来查找地图上两个坐标之间的路径。使用MongoDB集合中的mgo获取地图数据。

然而,它很慢。 1000米路线大约需要4秒钟。我已经计算了算法的不同部分,并得出结论,瓶颈是从数据库中取出的。或者确切地说:在从二进制数据到Go理解的数据结构的转换中。

我尝试尽可能少地执行请求,并多次线程化请求以使其更快,并且它在一定程度上有所帮助。但它并不像我希望的那么快。

似乎我做了一些根本错误的事情。任何建议都会有所帮助。

mongoDB中的数据结构:(从OSM获取的节点)

{ "_id" : NumberLong(194637483),
  "lat" : 55.7079899, 
  "lon" : 13.3756414,
  "neighbours" : [ NumberLong(1566264689), NumberLong(1566264806) ] 
}

Go中的数据结构

type Node struct {
    ID         int64   `bson:"_id" json:"id"`
    Lat        float64 `bson:"lat" json:"lat"`
    Lon        float64 `bson:"lon" json:"lon"`
    Neighbours []int64 `bson:"neighbours" json:"neighbours"`
}

获取数据的代码:

func addToBufferLong(buffer *WriteLockMap, session *mgo.Session, at, goal geo.Node, lowerLat, higherLat, lowerLon, higherLon float64) {
    c := session.DB("collectionName").C("nodes")
    query := c.Find(bson.M{"lat": bson.M{"$gt": lowerLat, "$lt": higherLat}, "lon": bson.M{"$gt": lowerLon, "$lt": higherLon}})

    var nodes []geo.Node
    query.All(&nodes)
    for _, node := range nodes {
        tmp := PathNode{0, node.DistanceTo(goal), 0, node}
        buffer.Lock()
        buffer.m[node.ID] = tmp
        buffer.Unlock()
    }
}

编辑:

多线程策略基于将我想要查询的区域分成4个不同的方块,象限,如果你愿意,并用addToBufferLong(...)单独进行分析

最近的打印件:

> time GOMAXPROCS=8 ./toystar
Starting A star
Thread A, count: 19657, db-fetch: 0.122792104s, parsing: 0.934650055s
Thread B, count: 19574, db-fetch: 0.274384302s, parsing: 1.196350664s
Thread C, count: 4197, db-fetch: 0.388197823s, parsing: 0.930109241s
Thread D, count: 9900, db-fetch: 0.540008325s, parsing: 0.93963728s

Total database fetch:  1.534268099 s
Total A star (with fetches):  1.854748244

real    0m1.907s

其中db-fetch测量以query:= c.Find(...)开头的行所花费的时间,并解析测量查询所需的时间。所有(&节点)

编辑2:

在堆栈溢出用户的帮助下,我成功地显着降低了执行时间。目前的打印输出:

> time GOMAXPROCS=8 ./toystar

Starting A star
Thread A: 0.210783141s
Thread B: 0.380938949s
Thread C: 0.441447793s
Thread D: 0.507361847s

Total database fetch:  0.507543875 s
number of fetches:  1
Total A star:  0.826343287s

real    0m0.860s

主要区别在于多线程策略并使用*mgo.Iter代替query.All(&nodes)

1 个答案:

答案 0 :(得分:2)

根据现有资料,我可以推断出这一点:

  1. 您的机器似乎很慢,可能是嵌入式设备?
  2. 您调用db-fetch的阶段实际上并不访问数据库。 c.Find(...)唯一能做的就是构建*mgo.Query值。该方法长6行。这不应该超过一毫秒。除非在数据库对象的内部会话状态上存在争用,但由于您只使用了4个goroutine,因此情况似乎并非如此。

    1. 瓶颈似乎是网络和/或反思
    2. query.All(&nodes)是在数据库上实际执行查询的地方。此外,此阶段分配所需的节点片段,然后通过反射迭代地将bson解码为结构定义。

      1. 您可以尝试一件事:*mgo.iter
      2. 您可以使用query.All(...)获取query.Iter()而不是*mgo.Iter,而不是批量遍历数据集。这可以通过更好地分配网络负载来提高性能。

        1. 使用geospacial索引,Mongo支持
        2. the documentation。也许你已经这样做了。如果没有,它可能会改善查找时间。

          1. 递归地将您的象限分成子分数。
          2. 我认为这一点很明显。分而治之,对吧? :)