2017-10-04 97 views
3

是一个很长时间的C++开发人员我刚开始着手Python中的算法。我目前正在分析我的代码,以了解如何在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

任何对此的帮助将超级赞赏。我想尽可能快地获得我的算法。

在此先感谢!干杯!

+0

请参阅https://wiki.python.org/moin/TimeComplexity –

+0

......顺便说一句,如果以数学为中心的工作负载的运行时性能是您的首要目标,那么Python可能不是您的语言。我可能会建议[Julia](https://julialang.org/)或[Go](https://golang.org/)? (Julia的网页涵盖了这两个基准)。 –

+0

太棒了。感谢您的资源。我目前正在为Blender开发一个插件,所以我没有替代Python的 – Marcel

回答

5

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

Python的时间,则该方法进行:

  • 创建新的功能框架(只有一个表达式时需要相当大的比例)
  • 全球名称查找(这是针对一个完成映射,本地名称使用数组)。
  • 属性查找,像mathutils.geometrymathutils.geometry.intersect_ray_tripoly.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作为将此代码转换为也可以本机速度运行的已编译扩展的简单途径。

+0

哇,非常感谢。多么详细和快速的答案。这绝对给了我很多见解 – Marcel