两个类似的实现退出了戏剧性的差异时间来运行

时间:2014-01-05 23:15:03

标签: python numpy runtime

我已经尝试了基本的cython教程here,看看速度有多大。 我还做了两个不同的python实现,它们在运行时显着不同。我已经测试了差异的运行时间,据我所知,它们没有解释整体运行时差异。

代码正在计算第一个kmax素数:

def pyprimes1(kmax):
    p=[]
    result = []
    if kmax > 1000:
        kmax = 1000
    k = 0
    n = 2
    while k < kmax:
        i = 0
        while i < k and n % p[i] != 0:
            i = i + 1
        if i == k:
            p.append(n)
            k = k + 1
            result.append(n)
        n = n + 1
    return result

def pyprimes2(kmax):
    p=zeros(kmax)
    result = []
    if kmax > 1000:
        kmax = 1000
    p=zeros(kmax)
    k = 0
    n = 2
    while k < kmax:
        i = 0
        while i < k and n % p[i] != 0:
            i = i + 1
        if i == k:
            p[k] = n
            k = k + 1
            result.append(n)
        n = n + 1
    return result  

正如您所看到的,两个实现之间的唯一区别在于p变量的使用,第一个是python列表,另一个是numpy数组。我使用IPython%timeit magic来测试timinigs。你觉得谁更好?这就是我得到的:

%timeit pyprimes1(1000)
10 loops, best of 3: 79.4 ms per loop

%timeit pyprimes2(1000)
1 loops, best of 3: 1.14 s per loop

这很奇怪而且令人惊讶,因为我认为预分配的numpy数组可能会更快。

我也测试过: 数组赋值:

%timeit p[100]=5
10000000 loops, best of 3: 116 ns per loop

数组选择:

%timeit p[100]
1000000 loops, best of 3: 252 ns per loop

这是两倍慢..也没想到。 数组初始化:

%timeit zeros(1000)
1000000 loops, best of 3: 1.65 µs per loop

列出追加:

%timeit p.append(1)
10000000 loops, best of 3: 164 ns per loop

列表选择:

%timeit p[100]
10000000 loops, best of 3: 56 ns per loop

所以列表选择似乎比数组选择快5倍。 我不知道这个数字如何加起来超过x10时差。虽然我们在每次迭代中进行选择,但速度只有5倍。

对数组和列表之间的时序差异以及两个实现之间的总体时间差异进行解释。或者我通过在增加长度列表上测量时间来使用%timeit错误?

顺便说一下,cython代码在3.5ms时表现最好。

2 个答案:

答案 0 :(得分:2)

第1000个素数是7919.因此,如果内部循环平均迭代kmax / 2次(非常粗略),则程序执行约。从阵列/列表中选择7919 *(1000/2)〜= 4 * 10 6 。如果第一个版本的列表中的单个选择需要56 ns,那么即使选择也不适合79 ms(0.056μs* 4 * 10 6 〜= 0.22 sec)。

这些纳秒时间可能不太准确。

顺便说一下,append的性能取决于列表的大小。在某些情况下,它可能会导致重新分配,但在大多数情况下,列表中有足够的可用空间,而且速度很快。

答案 1 :(得分:2)

Numpy的主要用例是对整个数组和切片执行操作,而不是单个元素。这些操作在C中实现,因此比等效的Python代码快得多。例如,

c = a + b

会比

快得多
for i in xrange(len(a)):
    c[i] = a[i] + b[i]

即使两种情况下变量都是numpy数组。

然而,像您正在测试的单元素操作可能比Python列表更差。 Python列表是结构的纯C数组,访问非常简单。

另一方面,访问numpy数组中的元素需要大量开销来支持多种原始数据格式和高级索引选项,以及其他原因。