Cython似乎通过减少时间分析器而不是核心代码的开销来提供加速?

时间:2018-03-14 23:57:33

标签: python-3.x performance cython cprofile

我试图学习并使用cython加速我的个人项目,但我发现了一些奇怪的东西。

示例:

试用http://nealhughes.net/cython1/

中的rbf_network示例
import numpy as np

# generate dummy data
n = 1000
a = np.random.uniform(low=0, high=10, size=n)
b = np.random.choice(2, 1000)

# map the function
start = time.time()
out = [a[i] if b[i] == 0 else -1/a[i] for i in range(n)]
print time.time() - start

File1和File2都包含:

import pyximport; pyximport.install()
from src.test_cython import rbf_network  # File1: /src/test_cython.pyx
# from src.test import rbf_network       # File2: /src/test.py
import time
import cProfile
import numpy as np

def fun():
    D = 5
    N = 1000
    X = np.array([np.random.rand(N) for d in range(D)]).T
    beta = np.random.rand(N)
    theta = 10
    rbf_network(X, beta, theta)

# With CProfile
cProfile.run('fun()', sort='cumtime')

# Without Cprofile
start = time.time()
fun()
print("Time without CProfile: ", time.time() - start)

File1上的输出(cythonized):

from math import exp
import numpy as np

def rbf_network(X, beta, theta):

    N = X.shape[0]
    D = X.shape[1]
    Y = np.zeros(N)

    for i in range(N):
        for j in range(N):
            r = 0
            for d in range(D):
                r += (X[j, d] - X[i, d]) ** 2
            r = r**0.5
            Y[i] += beta[j] * exp(-(r * theta)**2)

    return Y

File2上的输出(非cython):

     13 function calls in 3.920 seconds

Ordered by: cumulative time

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.000    0.000    3.920    3.920 {built-in method builtins.exec}
    1    0.000    0.000    3.920    3.920 <string>:1(<module>)
    1    0.000    0.000    3.920    3.920 run.py:138(fun)
    1    3.920    3.920    3.920    3.920 {src.test_cython.rbf_network}
    1    0.000    0.000    0.000    0.000 run.py:141(<listcomp>)
    6    0.000    0.000    0.000    0.000 {method 'rand' of 'mtrand.RandomState' objects}
    1    0.000    0.000    0.000    0.000 {built-in method numpy.core.multiarray.array}
    1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}


Time without CProfile:  3.899562120437622

简而言之,使用cProfile测量时,Cythonized代码似乎从13.19秒提高到3.920秒,但使用内置时间进行测量时,改进实际上仅为4.13秒至3.89秒。

Cython确实提供了一些加速(即使天真地使用)但是通过时间分析器测量加速似乎会使结果膨胀。也许这些时间分析器比使用核心代码更有益于使用cython。这是真的还是我做错了什么?

编辑:另外,我不确定为什么在cythonized代码中cIrofile没有跟踪{内置方法math.exp}。

1 个答案:

答案 0 :(得分:1)

python配置文件模块docs直接解决此问题

  

注意探查器模块旨在为给定程序提供执行配置文件,而不是用于基准测试目的(为此,有合理准确结果的时间)。这特别适用于针对C代码对Python代码进行基准测试:分析器引入了Python代码的开销,但不是C级函数的开销,因此C代码似乎比任何Python代码都快。