减少Python中的函数调用开销

rei*_*eer 6 python performance numpy cython overhead-minimization

我开发了一个应用程序,模拟N 个机器人在网格中移动,尝试以有限的步骤最大化访问的网格单元的数量,并在目标点相遇。一切正常,但速度太慢了。目前是python+numpy+mathplotlib。

最大机器人数量的软限制为 100(如果可以更高,那就太好了)。

为此,我做了以下简化的操作:

while steps > 0:
    for robot in robots:
        agent.calc(robot,steps)
Run Code Online (Sandbox Code Playgroud)

机器人是一个 1x2 numpy 数组(x 和 y 坐标)。

这里的代理决定要做什么。因为我需要即时改变战术和策略,所以我无法改变这个逻辑。

agent.calc一个接一个地就地更新机器人。

cProfiling 它返回以下内容。提取顶部

         39014272 function calls (39010490 primitive calls) in 150.314 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
 12417735   62.807    0.000   62.807    0.000 distance.py:8(taxicab_distance)
   124596   36.882    0.000   36.882    0.000 {numpy.core.multiarray.array}
   113657   30.204    0.000  100.800    0.001 logical_agent.py:16(choose_max_distance_to...)
 12417013    6.579    0.000   69.384    0.000 squaregrid.py:30(distance)
   113700    2.900    0.000  109.769    0.001 logical_agent.py:73(calc)
 11652363    2.625    0.000    2.625    0.000 {method 'append' of 'list' objects}
   161849    1.653    0.000    1.653    0.000 distance.py:11(euclidean_distance)
   113664    1.632    0.000    1.632    0.000 {sorted}
   114834    1.185    0.000    1.185    0.000 {method 'keys' of 'dict' objects}
   113700    0.695    0.000    1.134    0.000 squaregrid.py:19(neighbours)
Run Code Online (Sandbox Code Playgroud)

我为机器人实现了不同的环境,最重要的是squaregird。每个环境都有自己的距离函数,因为我打算使用不同的度量,即曼哈顿/出租车和欧几里德。我将距离函数提取到自己的distance.py文件中,因为我在多次使用它。

可以看到,taxicab_distance被称为很多,因为智能体需要评估机器人的四个邻居和它自己到目标点的距离,看看下一个位置是否仍然可以到达目标,并最大化到所有其他机器人的距离作为优化启发式。

该函数没有做任何花哨的事情,只是

def taxicab_distance(u, v):
    return np.abs(u[0] - v[0]) + np.abs(u[1] - v[1])
Run Code Online (Sandbox Code Playgroud)

我知道 python 的函数调用开销相当高,我认为这会影响性能。{numpy.core.multiarray.array}可以被忽略,我想我知道我在那里做错了什么。

距离调用链:agent ->environment.distance ->taxicab_distance

问题是,如何减少调用函数的开销呢?我强烈考虑使用 pythons c 扩展性,cython,更具体。它会起作用吗?还有其他原因导致它这么慢吗?

Yar*_*riv 5

首先,我将其重写为:

def taxicab_distance(u, v):
     return np.sum(np.abs(u - v))
Run Code Online (Sandbox Code Playgroud)

taxicab_distance你能同时计算多个机器人吗?


rei*_*eer 3

我用内联对其进行了基准测试,结果缩短了约 15 秒。最后,我用C++重写了数字运算,并使用cython进行集成。此后,只用了1秒的时间。

编辑:cpython - > cython