Python元素访问性能

时间:2017-10-04 13:25:55

标签: python performance

作为一名长期的C ++开发人员我刚开始研究Python中的算法。我目前正在分析我的代码,以了解如何在Python中有效编程。有一件事特别突出,对我来说,我很乐意得到专家的解释。

我为光线三角形交叉点编写了这个包装函数:

def rayIntersectsTriangle( origin , direction , meshData , poly , worldCoordinateVertices ):
    return mathutils.geometry.intersect_ray_tri( worldCoordinateVertices[ meshData.loops[ poly.loop_start ].vertex_index ],
                                                 worldCoordinateVertices[ meshData.loops[ poly.loop_start + 1 ].vertex_index ],
                                                 worldCoordinateVertices[ meshData.loops[ poly.loop_start + 2 ].vertex_index ],
                                                 direction , origin ) != None

在分析(使用cProfile)代码时,执行此功能的次数很多次,我得到以下结果:

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
15694126   22.314    0.000   25.812    0.000 ****.py:176(rayIntersectsPoly)
[...]
15694126    3.497    0.000    3.497    0.000 {built-in method mathutils.geometry.intersect_ray_tri}

为什么这个包装器增加了这么多开销呢?我唯一能看到的就是数组元素访问。来自C ++,这让我很困惑:D

对此的任何帮助都将非常感激。我想尽可能快地得到我的算法。

提前致谢!干杯!

1 个答案:

答案 0 :(得分:5)

相比之下,时间看起来很大,因为mathutils.geometry.intersect_ray_tri()。该方法在扩展中实现,并以本机速度执行。

该方法的Python时间转到:

  • 创建新的功能框架(只有一个表达式,时间占比较大)
  • 全局名称查找(这些是针对映射完成的,本地名称使用数组)。
  • 属性查找,例如mathutils.geometrymathutils.geometry.intersect_ray_tri以及poly.loop_start
  • 建立索引,worldCoordinateVertices[ ... ]

您可以通过在本地名称或默认参数中缓存其中一些结果来加快速度:

def rayIntersectsTriangle(
        origin, direction, meshData, poly, worldCoordinateVertices
        _intersect_ray_tri=mathutils.geometry.intersect_ray_tri):
    loop_start = poly.loop_start
    meshData_loops = meshData.loops
    return _intersect_ray_tri(
        worldCoordinateVertices[meshData_loops[loop_start].vertex_index],
        worldCoordinateVertices[meshData_loops[loop_start + 1].vertex_index],
        worldCoordinateVertices[meshData_loops[loop_start + 2].vertex_index],
        direction, origin) is not None

我还使用了is not None;这是一个建议用于测试None单例的指针操作。

这会导致8个属性查找下降到2,并删除mathutils的全局名称查找。

尽管如此,这些都是微优化,只有在真正产生影响时才会这样做(例如,在您的代码中调用该方法很多)。如果这确实是您的瓶颈,请考虑使用Cython作为将此代码转换为也可以以原生速度运行的编译扩展的简单途径。