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

Posted

技术标签:

【中文标题】Cython 似乎通过减少时间分析器而不是核心代码的开销来提供加速?【英文标题】:Cython seems to provide speed-up by reducing the overhead in time profiler rather than the core code? 【发布时间】:2018-03-14 23:57:32 【问题描述】:

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

例子:

尝试http://nealhughes.net/cython1/的rbf_network示例

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 和 File2 都包含:

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

File1 上的输出(cythonized):

     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

File2 上的输出(非 cython):

         1000014 function calls in 13.193 seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.000    0.000   13.193   13.193 built-in method builtins.exec
    1    0.000    0.000   13.193   13.193 <string>:1(<module>)
    1    0.000    0.000   13.193   13.193 run.py:138(fun)
    1    7.948    7.948   13.193   13.193 test.py:4(rbf_network)
  1000000    5.245    0.000    5.245    0.000 built-in method math.exp
    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 built-in method numpy.core.multiarray.zeros
    1    0.000    0.000    0.000    0.000 method 'disable' of '_lsprof.Profiler' objects


Time without CProfile:  4.139716863632202

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

Cython 确实提供了一些加速(即使是在天真的使用时),但通过时间分析器测量加速似乎夸大了结果。也许这些时间分析器通过使用 cython 而不是核心代码而受益。这是真的还是我做错了什么?

编辑:另外,我不确定为什么 cProfile 在 cythonized 代码中没有跟踪 built-in method math.exp。

【问题讨论】:

【参考方案1】:

python配置文件模块docs直接解决这个

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

【讨论】:

以上是关于Cython 似乎通过减少时间分析器而不是核心代码的开销来提供加速?的主要内容,如果未能解决你的问题,请参考以下文章

减少cython并行中的数组

Cython 代码分析

分析 Cython 代码时,啥是`stringsource`?

Cython 的功率谱

有效的 Cython cProfiling 是不是意味着编写许多子函数?

为整个程序启用 Cython 分析?