我正在尝试使用两个大小的双元组列表作为输入和输出来加速Cython中已经非常优化的函数。要做到这一点,我需要首先在纯C中使用它。
在python中以某种方式cython化了元组语法 ressembles 这个:
def f(inputList1, inputList2):
cdef double p, i10,i11,i20,i21,a0,a1
a0,a1=inputList1[-1]
for i10,i11 in inputList1:
outputList=[]
#some more computations involving a0 and a1
for i20,i21 in inputList2:
p=f(i10,i11,a0,a1,i21,i20) #f returns a double
if p==0:
outputList.append((i10,i21))
else if p>0:
outputList.append(g(i10,i21,i20,i21)) #g returns two outputs that are parsed as a two sized tuples automatically
if len(outputList)<1:
return []
#some more computations
a0, a1=i10, i11
return outputList
细节与速度和语法的重要性无关:它在for循环中使用元组解包来打破元组,并且可以使用append()附加整个元组,它也可以获取最后一个元素列表,它可以返回一个空列表。它还可以将g的两个输出转换为元组。
我正在尝试将所有的python改为纯C来提高速度或至少不会损害速度在我的脑海中它应该是可行的(也许我错了?)。因此,当g必须变为纯C时,必须返回一个对象(我猜多个输出是不可能的?)
我的第一个想法是使用std::vectors
和std::pairs
列表列表成为vector[pair[double,double]]
我修改了g以返回pair[double,double]
而不是两个双打
cdef vector[pair[double,double]] f(vector[pair[double,double]] inputList1, vector[pair[double,double]] inputList2):
cdef double p, i10,i11,i20,i21,a0,a1
#I have to add the pairs as I cannot use the for a,b in syntax
cdef pair[double,double] i1,i2,e
cdef vector[pair[double,double]] outputList, emptyList
a0,a1=inputList.back()
for i1 in inputList1:
i10=i1.first
i11=i1.second
outputList=emptyList
#some more computations involving a0 and a1
for i2 in inputList2:
i20=i2.first
i21=i2.second
p=f(i10,i11,a0,a1,i21,i20) #f returns a double
if p==0.:
outputList.push_back(i1) #I am now using push_back and not append
else if p>0.:
outputList.push_back(g(i10,i21,i20,i21)) #g now returns a pair
if outputList.size()<1:
return outputList
#some more computations
a0, a1=i10, i11
return outputList
一切都是纯粹的C但是慢3倍 !!!
我也尝试了std::list
和list[list[double]]
我的速度也减少了3倍!我使用i1.back()
和i1.front()
而不是第一和第二我想这也让我速度快。这是什么原因?是否有更好的C对象可供使用?是我正在使用的语法?明确地做i20=i2.first
等等是什么让它变得如此缓慢?
特别是g的语法现在看起来真的很愚蠢,也许瓶颈来自那里:
cdef pair[double,double] g(double a, double b, double c, double d):
#looks ugly that I have to define res
cdef pair[double,double] res
cdef double res_int
res_1=computations1(a,b,c,d)
res_2=computations2(a,b,c,d)
#looks ugly
res.first=res_1
res.second=res_2
return res
而不是像以前一样简单地返回res_1,res_2:
编辑:我重新编写了所有内容以对不同的解决方案进行基准测试:
-it结果列表[list [double]]对我来说不是一个选项,因为稍后在我的代码中我需要通过索引访问列表的特定元素
-vector [np.ndarray [DTYPE,ndim = 1]]不起作用我想你不能用Python对象形成一个向量
-vector [pair [double,double]]实际上确实比Python列表版本更快!
对于100000次迭代,Python版本总共 :
Python 版1.10413002968s
0.781275987625s (vector [pair [double,double]]) C 版本。
它仍然看起来非常难看,我仍然想听听这是否是正确的方法