我有一个时间关键的模型,我用Cython写的。我的Cython扩展的主要功能只有一个循环,根据Cython分析器(它以黄色表示Python调用的数量),唯一的“黄色”部分是当前我附加到Python列表中的部分。(我必须输出Python对象,因为我在Python脚本中调用我的Cython函数)。这是我的函数的基本思想(其余部分是多余的,我已经测试了该函数的每个部分,附加操作是瓶颈):
from libc.math cimport log
def main(some args):
cdef (some vars)
cdef list OutputList = []
# NB: all vars have declared types
for x in range(t):
(do some Cythonic stuff, some of which uses my cimport-ed log)
if condition is True:
OutputList.append(x) # this is the only 'yellow' line in my main loop.
return OutputList # return Python object to Python script that calls main()不幸的是,我不知道输出数组/列表/向量的长度(不管我最后使用的是什么)。但是,我可以将它设置为52560,这就是我在其他Python代码中调整它的大小的结果。我想在不设置输出数组的长度的情况下得到一个大幅度的速度提升,但是如果它阻碍了我,我会很高兴地抛出这个希望。
我还尝试在Cython中使用C++来使用C++数据结构(向量、队列等)。但是这样做就失去了我很好地移植日志的能力。我在Cython /wiki上看到,您可以在C++ Cython中编写一个“shim”模块来使用纯C函数,但是我不知道如何这样做,也找不到任何关于如何实现它的信息。
无论如何,我欢迎所有坚持我的问题的建议:
在Cython中构建未知大小的列表/数组/向量的最佳方法是什么?或者有一个明确的替代方案(例如解决一个已知长度的可迭代对象),使我的未知长度问题模拟?
更新
C++容器确实显示了比项分配更快的速度,而项分配确实显示了附加到列表和numpy数组之后的速度增长。最好的方法是使用C++容器,同时也能够对纯C functions...this进行加密,这样就可以避免慢下来的情况出现在libc.math之外,以获得快速的日志函数。
发布于 2011-09-13 16:48:36
在CPython中,追加python列表是一个很好的优化操作。Python不为每个元素分配内存,而是不断增加指向列表中对象的指针数组。因此,切换到Cython并不会对您有很大的帮助。
您可以在Cython中使用c++容器,如下所示:
from libc.math cimport log
from libcpp.list cimport list as cpplist
def main(int t):
cdef cpplist[int] temp
for x in range(t):
if x> 0:
temp.push_back(x)
cdef int N = temp.size()
cdef list OutputList = N*[0]
for i in range(N):
OutputList[i] = temp.front()
temp.pop_front()
return OutputList 你必须测试这是否加快了速度,但也许你不会获得太多的速度。
另一种方法是使用numpy数组。在这里,Cython在优化代码方面非常出色。因此,如果您可以使用numpy数组作为main的返回值,则应该考虑这一点,并将OutputList的构造和填充替换为一些Cython代码分配和填充numpy数组。
有关更多信息,请参见http://docs.cython.org/src/tutorial/numpy.html
问你是否需要帮助。
UPDATE:如果避免在两个循环中查找方法,代码应该会更快一些:
from libc.math cimport log
from libcpp.list cimport list as cpplist
def main(int t):
cdef cpplist[int] temp
push_back = temp.push_back
for x in range(t):
if x> 0:
push_back(x)
cdef int N = temp.size()
cdef list OutputList = N*[0]
front = temp.front()
pop_front = temp.pop_front()
for i in range(N):
OutputList[i] = front()
pop_front()
return OutputList 发布于 2011-09-22 19:03:35
t和v.size()很有用)
#cython: boundscheck=False, wraparound=False
from libc.math cimport log
from cython.parallel cimport prange
import numpy as pynp
cimport numpy as np
# copy declarations from libcpp.vector to allow nogil
cdef extern from "<vector>" namespace "std":
cdef cppclass vector[T]:
void push_back(T&) nogil
size_t size()
T& operator[](size_t)
def makearray(int t):
cdef vector[np.float_t] v
cdef int i
with nogil:
for i in range(t):
if i % 10 == 0:
v.push_back(log(i+1))
cdef np.ndarray[np.float_t] a = pynp.empty(v.size(), dtype=pynp.float)
for i in prange(a.shape[0], nogil=True):
a[i] = v[i]
return a第二部分是第一个循环的1%,因此在这种情况下优化它的速度是没有意义的。
<math.h>在我的系统上有extern "C" { ... },所以libc.math.log可以工作。
可以使用PyArray_SimpleNewFromData()来避免复制数据,因为需要自己管理数组的内存。
发布于 2011-09-13 17:52:03
您可以做的是计算有多少元素符合您的条件,然后为这些元素分配一个足够大的numpy数组。
# pseudo code
def main():
count = 0
for i in range(t):
if criteria:
count += 1
cdef numpy.ndarray[count] result
int idx =0
for i in range(t):
if criteria:
idx += 1
result[idx] = valuehttps://stackoverflow.com/questions/7403966
复制相似问题