Cython中C类型与编译时类型的区别
我刚接触Cython,正在学习如何与numpy结合使用,以加速代码。我在这个链接上跟着教程学。
我把他们的代码复制过来了:
from __future__ import division
import numpy as np
# "cimport" is used to import special compile-time information
# about the numpy module (this is stored in a file numpy.pxd which is
# currently part of the Cython distribution).
cimport numpy as np
# We now need to fix a datatype for our arrays. I've used the variable
# DTYPE for this, which is assigned to the usual NumPy runtime
# type info object.
DTYPE = np.int
# "ctypedef" assigns a corresponding compile-time type to DTYPE_t. For
# every type in the numpy module there's a corresponding compile-time
# type with a _t-suffix.
ctypedef np.int_t DTYPE_t
# The builtin min and max functions works with Python objects, and are
# so very slow. So we create our own.
# - "cdef" declares a function which has much less overhead than a normal
# def function (but it is not Python-callable)
# - "inline" is passed on to the C compiler which may inline the functions
# - The C type "int" is chosen as return type and argument types
# - Cython allows some newer Python constructs like "a if x else b", but
# the resulting C file compiles with Python 2.3 through to Python 3.0 beta.
cdef inline int int_max(int a, int b): return a if a >= b else b
cdef inline int int_min(int a, int b): return a if a <= b else b
# "def" can type its arguments but not have a return type. The type of the
# arguments for a "def" function is checked at run-time when entering the
# function.
#
# The arrays f, g and h is typed as "np.ndarray" instances. The only effect
# this has is to a) insert checks that the function arguments really are
# NumPy arrays, and b) make some attribute access like f.shape[0] much
# more efficient. (In this example this doesn't matter though.)
cimport cython
@cython.boundscheck(False)
def naive_convolve(np.ndarray[DTYPE_t, ndim=2] f, np.ndarray[DTYPE_t, ndim=2] g):
if g.shape[0] % 2 != 1 or g.shape[1] % 2 != 1:
raise ValueError("Only odd dimensions on filter supported")
assert f.dtype == DTYPE and g.dtype == DTYPE
# The "cdef" keyword is also used within functions to type variables. It
# can only be used at the top indendation level (there are non-trivial
# problems with allowing them in other places, though we'd love to see
# good and thought out proposals for it).
#
# For the indices, the "int" type is used. This corresponds to a C int,
# other C types (like "unsigned int") could have been used instead.
# Purists could use "Py_ssize_t" which is the proper Python type for
# array indices.
cdef int vmax = f.shape[0]
cdef int wmax = f.shape[1]
cdef int smax = g.shape[0]
cdef int tmax = g.shape[1]
cdef int smid = smax // 2
cdef int tmid = tmax // 2
cdef int xmax = vmax + 2*smid
cdef int ymax = wmax + 2*tmid
cdef np.ndarray[DTYPE_t, ndim=2] h = np.zeros([xmax, ymax], dtype=DTYPE)
cdef int s, t
cdef unsigned int x, y, v, w
# It is very important to type ALL your variables. You do not get any
# warnings if not, only much slower code (they are implicitly typed as
# Python objects).
cdef int s_from, s_to, t_from, t_to
# For the value variable, we want to use the same data type as is
# stored in the array, so we use "DTYPE_t" as defined above.
# NB! An important side-effect of this is that if "value" overflows its
# datatype size, it will simply wrap around like in C, rather than raise
# an error like in Python.
cdef DTYPE_t value
for x in range(xmax):
for y in range(ymax):
s_from = int_max(smid - x, -smid)
s_to = int_min((xmax - x) - smid, smid + 1)
t_from = int_max(tmid - y, -tmid)
t_to = int_min((ymax - y) - tmid, tmid + 1)
value = 0
for s in range(s_from, s_to):
for t in range(t_from, t_to):
v = <unsigned int>(x - smid + s)
w = <unsigned int>(y - tmid + t)
value += g[<unsigned int>(smid - s), <unsigned int>(tmid - t)] * f[v, w]
h[x, y] = value
return h
有一点我不太明白。我知道cdef
是用来定义C语言类型的,这个可以在这个Cython语言基础的链接里找到。不过,上面的例子还定义了一个编译时类型,叫做np.int_t,比如在那行cdef DTYPE_t value
中,DTYPE_t
实际上就是np.int_t
。
我的问题是:np.int
和np.int_t
有什么区别?这是不是类似于Python中的int
和ctypes.c_int
,但更具体于numpy?如果是这样的话,我直接用cdef int
代替cdef np.int_t
会不会一样?
另外,我测试了一下,如果把cdef DTYPE_t value
换成cdef int value
会发生什么。结果显示这两者之间没有区别。
这是原来的cdef DTYPE_t value
的结果:1次循环,10次中的最好结果是每次93.9毫秒。
这是修改后的cdef int value
的结果:1次循环,10次中的最好结果是每次93.8毫秒。
任何帮助都非常感谢!
1 个回答
5
np.int
是一个 Python 对象,它指向 Python 代码中的整数类型 dtype
。而 np.int_t
是一个在 Cython 中使用的 C 类型定义(typedef
),它只在 Cython 里存在。(我认为它对应的是 C 语言中的 long
,而不是 int
。)