Python 2.7中对象实例化极慢

5

我最近需要完成一个涉及多个坐标操作的任务。为了节省时间和简化代码,我定义了一个类来封装坐标对的行为。这个类看起来像这样:

class Vector (tuple) :
    def __init__ (self, value) :
        tuple.__init__ (self, value)


    def __add__ (self, other) :
        return Vector ((self [0] + other [0], self [1] + other [1]))

这使我能够编写如下代码(例如):
def translate (pointList, displacement) :
    return [point + displacement for point in pointList]

但是我的应用程序非常慢,比其他任务慢得多。我在算法实现中找不到任何低效之处,所以我进行了一个简单的测试,看一下Vector类的开销。我预计会有5%至15%之间的开销。

我的Vector类测试代码如下:

v = Vector ((0, 0))
d = Vector ((1, -1))
loopIdx = 3000000
while loopIdx > 0 :
    v = v + d
    loopIdx -= 1
print (v)

这通常需要运行以下时间:

real    0m8.440s
user    0m8.367s
sys     0m0.016s

为了对比,我运行了这段代码:

v = (0, 0)
dX = 1
dY = -1
loopIdx = 3000000
while loopIdx > 0 :
    v = ( v [0] + dX, v [1] + dY )
    loopIdx -= 1
print (v)

这段代码的运行时间是:
real    0m1.004s
user    0m0.995s
sys     0m0.006s

我是否犯了什么严重错误,或者在Python中使用类对象真的意味着你的应用程序运行时间会延长8倍以上吗?


可能不是类本身的问题,而是元组直接在C中实现,而你的类没有。 - Daniel Roseman
1
虽然不是回答问题,但是:你可以使用“复数”来代替你的“向量”类来表示二维坐标。加法、减法、绝对值(用于距离)等都包含在内。此外,这比使用元组(如你的第二种方法)快2-3倍。 - tobias_k
1
您可以考虑使用带有__slots__的类来最小化每个实例的内存占用。 - jonrsharpe
2
仅仅删除__init__对于语义没有任何影响,但可以使得测试该类时提升60%的速度。 - user319799
1
问题是:如果你为旋转函数创建一个complex的子类,那么你也必须重写所有其他方法,以返回你的子类而不是常规的complex。考虑到巨大的加速效果,我认为这是一个你应该接受的妥协。 - tobias_k
显示剩余6条评论
1个回答

1
并不是如何让你的类更快的答案,而是提供一种替代方案。
不必子类化元组并自己编写所有的add、sub等方法,您可以使用Python内置的复数类型complex来表示二维坐标,它已经具备了所有这些操作,正确且超级快速。
>>> %timeit vector_no_init()
1 loops, best of 3: 1.39 s per loop
>>> %timeit plain_tuple()
1 loops, best of 3: 403 ms per loop
>>> %timeit complex_nums()
1 loops, best of 3: 171 ms per loop

对于旋转,您可以使用复数乘法:只需将您的复数坐标与一个极形式下绝对值为1且相位等于所需旋转角度的复数相乘即可。 要旋转90度,只需乘以1j(逆时针)或-1j(顺时针)。对于所有其他角度,请使用cmath模块进行极坐标形式的转换。

>>> c = complex(4, 2)
>>> c * cmath.rect(1, math.radians(45))
(1.4142135623730954+4.242640687119285j)

然而,我建议不要complex进行子类化以使rotate成为该类的方法,因为在这种情况下,您还必须覆盖所有其他方法,如add,否则加法的结果将是一个常规复数,而不提供rotate方法。这将撤销所有那些性能增益,使其与您的Vector类一样慢。相反,只需创建一个函数rotate(complex, angle) -> complex

谢谢。初步结果显示,使用complex替换tuple的原始算术(无类)可以提高40%的性能。 - Terrible Tadpole

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接