python - Cython 性能基准

标签 python performance benchmarking cython

我正在尝试获取 cython 和 numpy 的 FLOPS 基准。为此我在 cython 中编写了一个程序。这是:

cimport numpy as np
import numpy as np
import time

cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def numpybenchmark():

    cdef np.ndarray[np.float64_t, ndim=2] m1 = np.random.rand(3,3)
    cdef np.ndarray[np.float64_t, ndim=1] m2 = np.random.rand(3)
    cdef np.ndarray[np.float64_t, ndim=1] res

    cdef int niters = 10000000
    cdef int x

    t1 = time.time()
    for x in range(niters):
        res = np.dot(m1, m2)
    t2 = time.time()
    cdef double numopsperloop = 9. + 6.
    cdef double totalops = numopsperloop * float(niters)
    cdef double mflops = totalops / (t2-t1) / 1024. / 1024.
    print 'Computed MFLops is: ' + str(mflops)

在我的机器上,我测量“计算的 MFLops 为:7.42390102416”。我的机器配备 Intel Core i7-6700HQ CPU @ 2.6 GHz,运行 Windows 10。

如果您想在您的计算机上运行它,请将代码保存在名为“benchmark.pyx”的文件中。然后创建一个名为“setup.py”的文件,其中包含以下内容:

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

setup(                                                                                           
    ext_modules = cythonize("benchmark.pyx"), 
    include_dirs=[numpy.get_include()]                                                           
)  

然后你应该能够使用“python setup.py build_ext --inplace”来编译它。在 Windows 上,这可能会有点困难,因为我遇到了可怕的“无法找到 vcvarsall.bat”错误,并且不得不花费大量精力来解决该问题。

这个性能对我来说似乎很差。我想知道是否有人可以在他们的平台上运行它并告诉我你会得到什么?或者指出我的代码中出现的任何对性能产生不利影响的明显错误?

谢谢!

最佳答案

Cython 实际上并没有消除 np.dot 上的任何 Python 调用开销。这涉及(请注意,该列表并不详尽,并且在某些地方可能略有错误,但它给出了要点):

  1. 找到要调用的np.dot:

    • 在全局命名空间中查找 np
    • np的命名空间中查找dot的字典。 (请注意,通过在函数内执行 dot = np.dot,然后调用 dot 可以消除上述所有内容)
    • dot 上查找 __call__。 (如果 dot 是 C/Fortran 编译函数,则可以通过更快的机制来完成)
  2. 打包为 np.dot 准备参数:

    • 创建一个元组,其中包含传递给 np.dot 的两个参数
    • 增加每个参数的引用计数。
  3. np.dot 然后处理参数...

    • 解压元组
    • 检查 numpy 数组中的每个参数。
    • 检查每个 numpy 数组的 dtype 是否相同,并根据 dtype 选择要调用的 BLAS 函数。
    • 检查数组维度并确保它们匹配。
  4. ...为输出参数分配空间...

    • 分配一个新的np.ndarray对象
    • 增加该引用计数
    • ndarray 中的物理数组分配空间
  5. ...调用 BLAS 运算,为您提供浮点运算...

  6. ...并减少所传递的输入参数的引用计数(检查是否应该释放任何参数,尽管不会)

  7. 您的调用函数必须:

    • 检查np.dot是否引发异常
    • 接收输出数组(这里可能有一些引用计数杂耍)
    • 减少 res 之前内容的引用计数
    • 释放 res 之前的内容,请记住,这至少是一个 2 步过程,因为该数组与 ndarray 持有者分开保存。

如果您想让其中的大部分内容(可能除了分配)与矩阵向量乘法相比变得微不足道,那么您需要在更大的数组上进行测量。您可以使用 np.dot 中的 out 可选参数来取消分配。如果您想让这一切消失,那么您可以使用 scipy Cython BLAS interface直接调用BLAS函数。

关于python - Cython 性能基准,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35347466/

相关文章:

python - 如何使用 Python 的 Xlib 将文本写入根窗口?

Python 多处理 - 了解每个进程进度的最佳方式

performance - HTTP 与 HTTPS 性能

python - 从 2D numpy 数组的 numpy 数组高效创建 block numpy 数组

haskell - `new-bench` 命令中的 CLI 参数位于 `cabal`

java - 如何使用 System.nanoTime() 准确地延迟循环迭代以达到每秒 1M 的频率?

python - 使用 pandas 进行文件操作

Python:如何在正则表达式中保留字母数字英语、拉丁字符?

Java 并行上传

java - RabbitMQ N 交换测试