6

我有一个数据集,它是一个大型未加权循环图循环发生在大约 5-6 条路径的循环中。它由大约 8000 个节点组成,每个节点有 1-6 个(通常大约 4-5 个)连接。我正在做单对最短路径计算,并实现了以下代码来进行广度优先搜索。

from Queue import Queue

q = Queue()
parent = {}
fromNode = 'E1123'
toNode = 'A3455'

# path finding
q.put(fromNode)
parent[fromNode] = 'Root'

while not q.empty():
  # get the next node and add its neighbours to queue
  current = q.get()
  for i in getNeighbours(current):
    # note parent and only continue if not already visited
    if i[0] not in parent:
      parent[i[0]] = current
      q.put(i[0])

  # check if destination
  if current == toNode:
    print 'arrived at', toNode
    break

上面的代码使用 Python 2.6 Queue 模块,getNeighbours() 只是一个子例程,它进行一次 MySQL 调用并将邻居作为元组列表返回,例如 (('foo',),('bar',))。SQL 调用很快。

代码工作正常,但是测试到大约 7 层的深度需要大约 20 秒才能运行(2.5GHz Intel 4GB RAM OS X 10.6)

我欢迎任何关于如何改进此代码的运行时间的评论。

4

4 回答 4

11

好吧,鉴于对评论的赞成票,我现在将其作为答案。

紧密循环中的 SQL肯定会减慢您的速度。我不在乎电话的速度有多快。想想看——你要求解析一个查询,运行一个查找——尽管如此,它仍然处于一个紧密的循环中。你的数据集是什么样的?您可以SELECT将整个数据集放入内存中,或者至少在 MySQL 之外使用它吗?

如果您在内存中使用该数据,您将看到显着的性能提升。

于 2009-11-18T02:44:36.197 回答
1

像这样的东西:

#!/usr/bin/env python

from Queue import Queue

def traverse_path(fromNode, toNode, nodes):
    def getNeighbours(current, nodes):
        return nodes[current] if current in nodes else []

    def make_path(toNode, graph):
        result = []
        while 'Root' != toNode:
            result.append(toNode)
            toNode = graph[toNode]
        result.reverse()
        return result

    q = Queue()
    q.put(fromNode)
    graph = {fromNode: 'Root'}

    while not q.empty():
        # get the next node and add its neighbours to queue
        current = q.get()
        for neighbor in getNeighbours(current, nodes):
            # use neighbor only continue if not already visited
            if neighbor not in graph:
                graph[neighbor] = current
                q.put(neighbor)

        # check if destination
        if current == toNode:
            return make_path(toNode, graph)
    return []

if __name__ == '__main__':
    nodes = {
        'E1123': ['D111', 'D222', 'D333', 'D444'],
        'D111': ['C01', 'C02', 'C04'],
        'D222': ['C11', 'C03', 'C05'],
        'D333': ['C01'],
        'C02': ['B1'],
        'B1': ['A3455']
    }
    result = traverse_path('E1123', 'A3455', nodes)
    print result

['E1123', 'D111', 'C02', 'B1', 'A3455']

如果您将 SQL 查询替换为列表字典(这将是棘手的部分),您将获得这种性能。

于 2009-11-18T04:03:00.843 回答
0

我敢打赌那台机器有不止一个核心,不是吗?并行运行它。

Python 线程

于 2009-11-18T02:37:53.440 回答
0

嗯,BFS 不涉及标记您已经看过的节点,以便您不再访问它们吗?

于 2009-11-18T02:38:13.077 回答