python - 对于基本总和计算,Cython 并不比 Python 快多少

标签 python cython python-2.x anaconda

我正在尝试遵循 Continuum Analytics blog 上给出的示例对 Python、Cython、Numba 进行基准测试以获得使用 for 循环计算的总和。不幸的是,我发现 Cython 比 Python 慢!

这是我的 Python 函数定义:

def python_sum(y):
    N = len(y)
    x = y[0]
    for i in xrange(1,N):
        x += y[i]
    return x

现在我的 Cython 函数:

def cython_sum(int[:] y):
    cdef int N = y.shape[0]
    cdef int x = y[0]
    cdef int i
    for i in xrange(1,N):
        x += y[i]
    return x

现在我有一个脚本可以提取这两个函数和基准:

import timeit
import numpy as np
import cython_sum
import python_sum

b = np.ones(10000)

timer = timeit.Timer(stmt='python_sum.python_sum(b)', setup='from __main__ import python_sum, b')
print "Python Sum    (ms): %g" % (timer.timeit(1)*1000)

timer = timeit.Timer(stmt='cython_sum.cython_sum(b)', setup='from __main__ import cython_sum, b')
print "Cython     (ms): %g" % (timer.timeit(1)*1000)

现在我的输出是:

Python Sum    (ms): 9.44624
Cython     (ms): 8.54868

根据上面链接的博客文章中的图表,我预计速度会提高 100 到 1000 倍,但我所看到的只是 Cython 比普通 Python 快一点点。

我是不是做错了什么?这似乎是一个带有简单函数定义的非常基本的问题,显然很多人都使用 Cython 取得了巨大的成功,所以很明显错误一定出在我身上。谁能阐明这一点并告诉我我做错了什么? 谢谢!

最佳答案

我不确定你为什么会得到那个结果。正如评论者所说,您的代码按原样甚至不应该工作,因为您会将 float 传递给需要 int 的函数。也许您在同一目录中留下了一个 cython_sum.py 文件?

我做了以下事情。我创建了一个 python_sum.py,其中包含您对 python_sum 的确切定义。然后我稍微更改了您的 Cython 代码:

cython_sum.pyx:

def cython_sum(long[:] y):    #changed `int` to `long`
    cdef int N = y.shape[0]
    cdef int x = y[0]
    cdef int i
    for i in xrange(1,N):
        x += y[i]
    return x

我制作了一个安装文件来构建 Cython 模块:

setup.py:

from distutils.core import setup
from Cython.Build import cythonize

setup(
  name = 'Cython sum test',
  ext_modules = cythonize("cython_sum.pyx"),
)

我使用 python setup.py build_ext --inplace 构建了模块。接下来,我运行了您的测试代码并进行了一些修改:

测试.py:

import timeit
import numpy as np
import cython_sum
import python_sum

# ** added dtype=np.int to create integers **
b = np.ones(10000, dtype=np.int)    

# ** changed .timeit(1) to .timeit(1000) for each one **
timer = timeit.Timer(stmt='python_sum.python_sum(b)', setup='from __main__ import python_sum, b')
print "Python Sum    (ms): %g" % (timer.timeit(1000)*1000)

timer = timeit.Timer(stmt='cython_sum.cython_sum(b)', setup='from __main__ import cython_sum, b')
print "Cython        (ms): %g" % (timer.timeit(1000)*1000)

我得到了以下结果:

$ python test.py
Python Sum    (ms): 4111.74
Cython        (ms): 7.06697

现在这是一个很好的加速!


此外,请遵循概述的指南 here ,我能够获得额外的(小的)加速:

cython_fast_sum.pyx:

import numpy as np
cimport numpy as np

DTYPE = np.int
ctypedef np.int_t DTYPE_t

def cython_sum(np.ndarray[DTYPE_t, ndim=1] y):
    cdef int N = y.shape[0]
    cdef int x = y[0]
    cdef int i
    for i in xrange(1,N):
        x += y[i]
    return x

setup_fast.py:

from distutils.core import setup
from Cython.Build import cythonize
import numpy as np

setup(
  name = 'Cython fast sum test',
  ext_modules = cythonize("cython_fast_sum.pyx"),
  include_dirs = [np.get_include()],
)

测试.py:

import timeit
import numpy as np
import cython_sum
import cython_fast_sum

b = np.ones(10000, dtype=np.int)

# ** note 100000 runs, not 1000 **
timer = timeit.Timer(stmt='cython_sum.cython_sum(b)', setup='from __main__ import cython_sum, b')
print "Cython naive  (ms): %g" % (timer.timeit(100000)*1000)

timer = timeit.Timer(stmt='cython_fast_sum.cython_sum(b)', setup='from __main__ import cython_fast_sum, b')
print "Cython fast   (ms): %g" % (timer.timeit(100000)*1000)

结果:

$ python test.py
Cython naive  (ms): 676.437
Cython fast   (ms): 645.797

关于python - 对于基本总和计算,Cython 并不比 Python 快多少,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21866182/

相关文章:

python - 如何使用 json.dumps() 将嵌套字典中的所有 int 转换为 str?

Python:将 XML 文件上传到 MySQL 数据库

python - 我需要创建一个程序,输入字符串列表,并输出整数、 float 等的数量

python - 这个cython代码可以优化吗?

c - `double(double)` 和 `double (*)(double)` 有什么区别

Python:Jupyter Notebook 中的 pretty-print

python - 关于python编码的问题

python - Google pydrive 将文件上传到特定文件夹

python - 为什么这个简单附加函数的 Cython 实现比 Numba 慢?

python - unpack_from 需要至少 4 个字节的缓冲区