Python,更快地使用类属性,还是函数中的变量?

时间:2013-11-03 21:32:08

标签: python numpy

在Python中,理论上,哪个方法应该更快test1test2(假设x的值相同)。我尝试使用%timeit,但看到的差别很小。

import numpy as np

class Tester():

    def __init__(self):
        self.x = np.arange(100000)

    def test1(self):
        return np.sum(self.x * self.x )

    def test2(self,x):
        return np.sum(x*x)

2 个答案:

答案 0 :(得分:7)

在Python的任何实现中,时间将绝大多数由两个向量的乘法控制,每个向量具有100,000个元素。与此相比,其他一切都是噪音。如果你真的对测量其他开销很感兴趣,那么使矢量小得多。

在CPython中,test2()很可能会更快一点。它有一个“额外”参数,但是参数是以“C速度”解压缩的,所以这并不重要。通过LOAD_FAST操作码访问参数的方式与局部变量相同,这是一种简单的array[index]访问。

test1()中,self.x的每个实例都会在字典self.__dict__中查找字符串“x”。这比索引数组访问慢。但与冗长的乘法所花费的时间相比,它基本上没什么。

答案 1 :(得分:1)

我知道这一点错过了问题的重点,但是既然你用numpy标记问题并且正在考虑大型阵列的速度差异,我想我会提到有更快的解决方案完全不同的东西。

所以,你正在做的是一个点积,所以使用numpy.dot,它是通过外部库(LAPACK?)的乘法和求和构建的(为方便起见,我将使用语法虽然@Tim的回答是test1,但因为不需要传递额外的论据。)

def test3(self):
    return np.dot(self.x, self.x)

或者甚至更快(当然更一般):

def test4(self):
    return np.einsum('i,i->', self.x, self.x)

以下是一些测试:

In [363]: paste
class Tester():
    def __init__(self, n):
        self.x = np.arange(n)
    def test1(self):
        return np.sum(self.x * self.x)
    def test2(self, x):
        return np.sum(x*x)
    def test3(self):
        return np.dot(self.x, self.x)
    def test4(self):
        return np.einsum('i,i->', self.x, self.x)
## -- End pasted text --

In [364]: t = Tester(10000)

In [365]: np.allclose(t.test1(), [t.test2(t.x), t.test3(), t.test4()])
Out[365]: True

In [366]: timeit t.test1()
10000 loops, best of 3: 37.4 µs per loop

In [367]: timeit t.test2(t.x)
10000 loops, best of 3: 37.4 µs per loop

In [368]: timeit t.test3()
100000 loops, best of 3: 15.2 µs per loop

In [369]: timeit t.test4()
100000 loops, best of 3: 16.5 µs per loop

In [370]: t = Tester(10)

In [371]: timeit t.test1()
100000 loops, best of 3: 16.6 µs per loop

In [372]: timeit t.test2(t.x)
100000 loops, best of 3: 16.5 µs per loop

In [373]: timeit t.test3()
100000 loops, best of 3: 3.14 µs per loop

In [374]: timeit t.test4()
100000 loops, best of 3: 6.26 µs per loop

谈到小的,几乎语法上的速度差异,考虑使用方法而不是独立函数:

def test1b(self):
    return (self.x*self.x).sum()

给出:

In [385]: t = Tester(10000)

In [386]: timeit t.test1()
10000 loops, best of 3: 40.6 µs per loop

In [387]: timeit t.test1b()
10000 loops, best of 3: 37.3 µs per loop

In [388]: t = Tester(3)

In [389]: timeit t.test1()
100000 loops, best of 3: 16.6 µs per loop

In [390]: timeit t.test1b()
100000 loops, best of 3: 14.2 µs per loop