【问题标题】:Reducing function call overhead in python减少python中的函数调用开销
【发布时间】:2014-01-01 14:45:05
【问题描述】:

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

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

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

while steps > 0:
    for robot in robots:
        agent.calc(robot,steps)

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

这里的代理决定做什么。由于我需要即时切换战术和策略,我无法移动那个逻辑。

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

cProfiling 它返回following。提取顶部

         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)

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

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

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

def taxicab_distance(u, v):
    return np.abs(u[0] - v[0]) + np.abs(u[1] - v[1])

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

距离调用链:代理 -> environment.distance -> 出租车距离

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

【问题讨论】:

  • 我做了很多工作,调用函数的开销很大,因为它几乎肯定由函数完成的实际工作所支配。
  • 作为实验,暂时停止使用taxicab_distance。相反,直接执行函数的代码:np.abs(u[0] - v[0]) + np.abs(u[1] - v[1])。它是否以明显的方式帮助性能?我的猜测是,你应该追求大(更好的算法、缓存策略等),而不是小(微优化,如函数调用开销)。
  • 您是否在利用矢量化操作?它看起来不像。如果你不这样做,使用 NumPy 实际上会比使用常规列表慢。
  • method 'keys' of 'dict' objects - 这不太可能对您的运行时产生重大影响,但您为什么要调用该方法?大多数时候,这是不必要的。如果你想遍历字典的键,只需使用for key in d
  • @user2357112 我不需要遍历 dict 键,我将它们存储起来以便以后为它们设置动画。对于每一步,我都会对 matplotlib animate 的网格单元和机器人位置进行快照。

标签: python performance numpy cython overhead-minimization


【解决方案1】:

首先,我将其重写为:

def taxicab_distance(u, v):
     return np.sum(np.abs(u - v))

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

【讨论】:

  • 完全正确。要利用 numpy 的性能优势,您需要对代码进行矢量化;它将内部循环从 python 提升到 C 级别。
  • 如何矢量化我的 agent.calc(robot,steps) ?底层数据结构是一个机器人数组(二维点),我可能会返回调用的值而不是就地更新。
  • 您需要向我们展示 agent.calc 的作用。我建议创建一个问题,例如“如何矢量化 ...”
【解决方案2】:

我用内联对它进行了基准测试,它起飞了大约 15 秒。最后,我重写了 C++ 中的数字运算并使用 cython 进行集成。之后,只用了 1 秒。

编辑:cpython -> cython

【讨论】:

  • 你的意思是“cpython”还是别的什么?
  • 我的意思是 cython 从 Python 调用 C++。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-02
  • 2014-04-10
相关资源
最近更新 更多