如何调用cdef方法

时间:2019-01-14 01:30:24

标签: cython

我想调用我的cdef方法并尽可能提高程序速度。我不想使用cpdef(下面解释原因)。最终,我想访问属于我的Cython扩展成员的cdef方法(其中一些返回void)。

我尝试遵循this example,这给我的印象是,可以通过为其编写Python(cdef)包装程序来调用def函数。

我无法重现这些结果,所以我为自己尝试了一个不同的问题(将所有数字从0到n求和)。

当然,我正在看documentation,它说

  

指令cpdef使该方法的两个版本可用。 Cython的使用速度较快,Python的使用速度较慢。

及以后(重点是我的)

  

与为cdef方法提供python包装器相比,它做的要强得多:与cdef方法不同,cpdef方法可以被Python子类中的方法和实例属性完全覆盖。 与cdef方法相比,它增加了一些调用开销

那么如何使用cdef函数而又没有cpdef函数的额外调用开销呢?

在此问题末尾的代码处,我得到以下结果:

def/cdef:
273.04207632583245
def/cpdef:
304.4114626176919
cpdef/cdef:
0.8969507060538783

不知何故,cpdefcdef快。对于n <100,我偶尔可以得到cpdef/cdef> 1,但这很少见。我认为这与将cdef函数包装在def函数中有关。这就是我链接的示例所做的事情,但是与使用cdef相比,使用cpdef的性能要好。

我很确定这不是包装cdef函数的方式,同时避免了cpdef的额外开销(其来源未明确记录)。

现在,代码:

setup.py

from setuptools import setup, Extension
from Cython.Build import cythonize

pkg_name = "tmp"

compile_args=['-std=c++17']

cy_foo = Extension(
        name=pkg_name + '.core.cy_foo',
        sources=[
            pkg_name + '/core/cy_foo.pyx',
        ],
        language='c++',
        extra_compile_args=compile_args,
)

setup(
    name=pkg_name,
    ext_modules=cythonize(cy_foo,
                          annotate=True,
                          build_dir='build'),
    packages=[
        pkg_name,
        pkg_name + '.core',
    ],
)

foo.py

def foo_def(n):
    sum = 0
    for i in range(n):
        sum += i
    return sum

cy_foo.pyx

def foo_cdef(n):
    return foo_cy(n)

cdef int foo_cy(int n):
    cdef int sum = 0
    cdef int i = 0
    for i in range(n):
        sum += i
    return sum

cpdef int foo_cpdef(int n):
    cdef int sum = 0
    cdef int i = 0
    for i in range(n):
        sum += i
    return sum

test.py

import timeit
from tmp.core.foo import foo_def
from tmp.core.cy_foo import foo_cdef
from tmp.core.cy_foo import foo_cpdef

n = 10000

# Python call
start_time = timeit.default_timer()
a = foo_def(n)
pyTime = timeit.default_timer() - start_time

# Call Python wrapper for C function
start_time = timeit.default_timer()
b = foo_cdef(n)
cTime = timeit.default_timer() - start_time

# Call cpdef function, which does more than wrap a cdef function (whatever that means)
start_time = timeit.default_timer()
c = foo_cpdef(n)
cpTime = timeit.default_timer() - start_time

print("def/cdef:")
print(pyTime/cTime)
print("def/cpdef:")
print(pyTime/cpTime)
print("cpdef/cdef:")
print(cpTime/cTime)

0 个答案:

没有答案