我有一个数据集是一个很大的未加权循环图。循环发生在大约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调用,并将邻居作为元组列表返回,例如: (( '富',),( '巴',))。 SQL调用很快。
代码工作正常但是测试到大约7层的深度需要大约20秒才能运行(2.5GHz Intel 4GB RAM OS X 10.6)
我欢迎任何有关如何改善此代码运行时间的评论。
答案 0 :(得分:11)
好吧,鉴于评论的赞成,我现在就回答。
紧密循环中的SQL 绝对会让你失望。我不在乎通话速度有多快。想一想 - 你要求解析一个查询,运行一个查询 - 尽可能快,它仍然处于一个紧密的循环中。你的数据集是什么样的?您可以将整个数据集SELECT
放入内存中,或者至少在MySQL之外使用它吗?
如果您在内存中使用该数据,您将看到显着的性能提升。
答案 1 :(得分: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查询(这将是棘手的部分),您将获得此性能。
答案 2 :(得分:0)
我敢打赌机器有多个核心,不是吗?并行运行它。
答案 3 :(得分:0)
嗯,BFS是否涉及标记你已经看过的节点,所以你不再访问它们了?