我想调用我的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
不知何故,cpdef
比cdef
快。对于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)