Numpy 分析Cython代码

分析Cython代码,我们将分析用来计算欧拉常数近似值的Cython代码和NumPy代码。所需的计算公式请见http://en.wikipedia.org/wiki/E_%28mathematical_constant%29。

具体步骤

下面介绍怎样分析Cython代码。为此,请执行以下步骤。

  • 用NumPy近似计算e

用NumPy近似计算e时,需要执行下列步骤。

  1. 创建一个由从1到n-1的自然数构成的数组(本例中n的默认值是40)。
  2. 计算数组的累积连乘,等同于求阶乘。
  3. 求取阶乘的倒数。
  4. 应用上述维基百科页面中的公式。

最后要加上标准的性能分析代码。具体代码如下:

这段代码在Windows平台上运行报错,原因是,默认情况下数组arr的数据类型是int32,不能容纳太大的计算结果。因此建议创建数组时,使用语句arr = numpy.arange(1, n,dtype=numpy.uint64)

import numpy
import cProfile
import pstats

def approx_e(n=40):
    # 创建数组[1, 2, ... n-1]
    arr = numpy.arange(1, n) 

     # 计算阶乘,并把计算结果转换为浮点数。
     arr = arr.cumprod().astype(float)

     # 取倒数1/n
     arr = numpy.reciprocal(arr)

     print 1 + arr.sum() 

cProfile.runctx("approx_e()", globals(), locals(), "Profile.prof")

s = pstats.Stats("Profile.prof")
s.strip_dirs().sort_stats("time").print_stats()

常数e近似计算的结果和性能分析的结果如下所示:

2.71828182846

        7 function calls in 0.000 CPU seconds

Ordered by: internal time

ncalls tottime percall cumtime percall filename:lineno(function)
    1   0.000   0.000   0.000   0.000 numpy_approxe.py:5(approx_e)
    1   0.000   0.000   0.000   0.000 {method 'cumprod' of 'numpy.ndarray' objects}
    1   0.000   0.000   0.000   0.000 {numpy.core.multiarray.arange}
    1   0.000   0.000   0.000   0.000 {method 'sum' of 'numpy.ndarray' objects}
    1   0.000   0.000   0.000   0.000 {method 'astype' of 'numpy.ndarray' objects}
    1   0.000   0.000   0.000   0.000 <string>:1(<module>)
    1   0.000   0.000   0.000   0.000 {method 'disable' of '_lsprof.Profiler' objects}

  • 用Cython近似计算e

和上述用NumPy近似计算e的过程一样,Cython代码使用相同的算法,只是在具体实现上有一些差别。和NumPy相比,由于缺少合适的便捷函数,我们需要用到for循环。而且,我们需要指明某些变量的类型。.pyx文件的具体代码如下。

def approx_e(int n=40):
    cdef double sum = 0.
    cdef double factorial = 1.
    cdef int k
    for k in xrange(1,n+1):
        factorial *= k
        sum += 1/factorial
    print 1 + sum

下列Python程序首先引入了Cython模块,然后做了一些相关的性能分析。

import pstats
import cProfile
import pyximport
pyximport.install()

import approxe
cProfile.runctx("approxe.approx_e()", globals(), locals(), "Profile.prof")

s = pstats.Stats("Profile.prof")
s.strip_dirs().sort_stats("time").print_stats()

Cython代码的分析结果如下:

2.71828182846

    3 function calls in 0.000 CPU seconds

    Ordered by: internal time

    ncalls tottime percall cumtime percall filename:lineno(function)
        1   0.000   0.000   0.000   0.000 {approxe.approx_e}
        1   0.000   0.000   0.000   0.000 <string>:1(<module>)
        1   0.000   0.000   0.000   0.000 {method 'disable' of '_lsprof.Profiler' objects}

攻略小结

我们分别分析了NumPy和Cython代码。NumPy在执行速度方面已经做了深度优化,NumPy程序和Cython程序都表现出了良好的性能,对此我们不应觉得意外。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程