cython:函数有各种类型的参数



我正试图将一个旧的Python代码修改为Cython以提高速度。一个类有一个init函数,允许各种类型的参数:

class dRect:
def __init__(self, *args):
if len(args) == 1: # actual input is a list of four float numbers
self.x0, self.y0, self.x1, self.y1 = args[0]
elif len(args) == 4:  # actual input is four float numbers
self.x0, self.y0, self.x1, self.y1 = args
# sample of initiating dRect instance
a = dRect([0, 1, 2, 3])
b = dRect(0, 1, 2, 3)

将其修改为Cython代码的正确方法是什么?或者我应该深入研究文档的哪一部分?谢谢

速度的大小(在任何情况下(取决于你被允许做什么(在我的情况下,最多提升10倍(。

  1. Cdef你的课。cdefed类将比非cdef类更快(请参阅下面测试中的MyCyClass与MyPyClass(
  2. 在cdefed类的构造函数中,传递Python浮点值比传递Python整数更可取。如果传入Python浮点而不是Python整数,则构造函数会更快。可能是因为将python浮点转换为double比将python整数转换为double
  3. 在免费的cdef函数中使用__new__((进行快速实例化,如果可以避免的话,可以避免使用元组进行初始化

测试:


cdef class MyCyClass:
cdef public double x0
cdef public double x1
cdef public double x2
cdef public double x3

def __init__(self, *args):
self.x0 = args[0]
self.x1 = args[1]
self.x2 = args[2]
self.x3 = args[3]

class MyPyClass:
def __init__(self, *args):
self.x0 = args[0]
self.x1 = args[1]
self.x2 = args[2]
self.x3 = args[3]
cdef new_MyCyClass_from_seq(args):
my_obj = MyCyClass.__new__(MyCyClass)
init_MyCyClass_from_seq(my_obj, args)
cdef init_MyCyClass_from_seq(MyCyClass my_obj, args):
my_obj.x0 = args[0]
my_obj.x1 = args[1]
my_obj.x2 = args[2]
my_obj.x3 = args[3]

cdef new_MyCyClass_from_double(double x0, double x1, double x2,  double x3):
my_obj = MyCyClass.__new__(MyCyClass)
init_MyCyClass_from_double(my_obj, x0, x1, x2, x3)

cdef init_MyCyClass_from_double(MyCyClass my_obj, double x0, double x1, double x2,  double x3):
my_obj.x0 = x0
my_obj.x1 = x1
my_obj.x2 = x2
my_obj.x3 = x3
def timefunc(name):
def timedecorator(f):
cdef Py_ssize_t L, i
print("Running", name)
for L in [1, 10, 100, 1000, 10000]:
start = time.perf_counter() 
f(L)
end = time.perf_counter()
print(format((end-start) / loops * 1e6, "2f"), end=" ")
sys.stdout.flush()
print("μs")
return timedecorator
print()
print("INITIALISATIONS")
cdef Py_ssize_t loops = 100000
@timefunc("use constructor of non-cdef class with type(input) = float")
def _(Py_ssize_t L):
cdef Py_ssize_t i

my_obj = MyPyClass(1., 2., 3., 4.)

for i in range(loops):
my_obj = MyPyClass(1., 2., 3., 4.)

return my_obj


@timefunc("use constructor (cdef) with type(input) = float")
def _(Py_ssize_t L):
cdef MyCyClass my_obj = MyCyClass(1., 2., 3., 4.)
cdef Py_ssize_t i

for i in range(loops):
# Notice the decimal place to denote 
my_obj = MyCyClass(1., 2., 3., 4.)

return my_obj

@timefunc("use constructor (cdef) with type(input) = int")
def _(Py_ssize_t L):
cdef MyCyClass my_obj = MyCyClass(1, 2, 3, 4)
cdef Py_ssize_t i

for i in range(loops):
my_obj = MyCyClass(1, 2, 3, 4)

return my_obj


@timefunc("use new (cdef) with double init, input is double")
def _(Py_ssize_t L):
cdef MyCyClass my_obj = MyCyClass(1, 2, 3, 4)
cdef Py_ssize_t i

for i in range(loops):
my_obj = new_MyCyClass_from_double(1., 2., 3., 4.)

return my_obj    


@timefunc("use new (cdef) with double init, input is int")
def _(Py_ssize_t L):
cdef MyCyClass my_obj = MyCyClass(1, 2, 3, 4)
cdef Py_ssize_t i

for i in range(loops):
new_MyCyClass_from_double(1, 2, 3, 4)

return my_obj    

@timefunc("use new (cdef) and tuple init")
def _(Py_ssize_t L):
cdef MyCyClass my_obj = MyCyClass(1., 2., 3., 4.)
cdef Py_ssize_t i

for i in range(loops):
my_obj = new_MyCyClass_from_seq((1., 2., 3., 4.))

return my_obj

以下是我的时间

正在运行类型为(input(=float 的非cdef类的use构造函数

  • 0.194803 0.199249 0.196051 0.2012200.265174μs(最慢(

运行类型(input(=float 的use构造函数(cdef(

  • 0.044000 0.048895 0.044641 0.045356 0.048148μs

运行类型(input(=int 的use构造函数(cdef(

  • 0.090032 0.169924 0.089831 0.090147 0.091007μs

运行带有双init的use new(cdef(,输入为双

  • 0.026093 0.025533 0.029145 0.0236390.024517μs(最快(

运行带有双init的use new(cdef(,输入为int

  • 0.025054 0.024114 0.024084 0.025460 0.024183μs(最快,相当于上述(

运行use new(cdef(和tuple init

  • 0.042559 0.042985 0.042348 0.043527 0.043123μs

最新更新