我有一个纯粹用Python编写的A *规划算法(在路径规划中使用这个优秀的resource)。具有相关移动和成本方法的网格类定义如下:
class SquareGrid:
def __init__(self, width, height):
self.width = width
self.height = height
self.walls = []
self.weights = []
def in_bounds(self, id):
(x, y) = id
return 0 <= x < self.width and 0 <= y < self.height
def passable(self, id):
return id not in self.walls
def neighbors(self, id):
(x, y) = id
results = [(x + 1, y), (x + 1, y - 1), (x, y - 1), (x - 1, y - 1), (x - 1, y), (x - 1, y + 1), (x, y + 1), (x + 1, y + 1)]
if (x + y) % 2 == 0: results.reverse() # aesthetics
results = [r for r in results if self.in_bounds(r)]
results = [r for r in results if self.passable(r)] # this is where things slow down
return results
def cost(self, from_node, to_node):
return (to_node[0] - from_node[0])**2 + (to_node[1] - from_node[1])**2
现在,我想使用Cython的静态编译器优点加快执行速度。一种选择是在Cython中使用静态类型重写整个事物。我使用cProfiler分析纯Python代码以查看瓶颈在哪里,并且不足为奇的是,大约70%的总执行时间进入neighbors
方法(计算当前节点周围的有效邻居节点)。更具体地说,对于给定的玩具示例,neighbors
中的列表理解行调用passable
超过33,000次。 passable
检查其参数中给出的节点是否标记为&#34;障碍&#34;或者不通过搜索SquareGrid
的障碍知识(SquareGrid.walls
,位置元组列表)并相应地返回布尔值。在我看来,仅仅通过优化这种特殊方法,我就可以获得显着的速度提升。所以我开始在Cython中重写passable
。
我在Cython和C / C ++中一般都是一个完整的菜鸟,所以如果有任何关于理解这个东西是如何运作的错误,我会很感激。我创建了一个pyrex文件passable_cy.pyx
,希望使用Cython / GCC ++编译它然后将它绑定到主脚本中的SquareGrid
对象就足够了。这就是我定义passable_cy.pyx
:
cpdef bint passable(object self, tuple id):
return id not in self.walls
随附的setup.py
文件:
from distutils.core import setup
from Cython.Build import cythonize
setup(name="cynthonized_passable", ext_modules=cythonize(['passable_cy.pyx']),)
这就是我在主要的A * python脚本中将新的cynthonized方法绑定到SquareGrid
的方法:
g = SquareGrid(100, 100) # create grid with dimensions 100x100
g.passable = types.MethodType(passable_cy.passable, g)
一切正确编译,整个事情没有问题。没有任何速度提升,我有点期待(看起来太简单了)。我该如何从这里开始?这种绑定方法的东西是最好的方法吗?我确信可以在passable_cy.pyx
中完成更多工作,但我不熟悉C / C ++以了解该怎么做。