Cython 初探及关于性能提升的初步讨论

Cython 可以通过强类型 大大加快Python代码的运行效率:
简单例子:
pure python
def f(x):
return x ** 2 - x 


def intergrate_f(a, b, N):
s = 0
dx = (b - a)/ N
for i in range(N):
s += f(a + i * dx)


return s * dx
 
print intergrate_f(-2.5, 10.5, 10000000)



Cython:
def f(double x):
return x ** 2 - x 


def intergrate_f(double a, double b, int N):
cdef int i 
cdef double s, dx 
s = 0 
dx = (b-a)/N 
for i in range(N):
s += f(a + i * dx)
return s * dx




将上述代码用Setup编译成Python包后 调用执行,
当使用pure Python 时耗时4.5s Cython耗时0.96s


这里cdef 是c相应类型的定义
这里还提供了对于异常的问题,当定义强类型函数时,一般需要指定exception,
值 当返回相应的exception值时说明产生了异常,否则Cython对于特殊的cdef返回值函数
是不具备异常提醒机制的。


Cython 用于提升np.ndarray相关的性能的方法在于指定数据类型
cdef np.ndarray 及对ndarray下标访问时 如指定下标cdef int i
应该使用转型<unsigned int> i 代替i进行下标访问。


使用Cython 可以大大加快Python代码运行
这一般限于对于底层的一些C类型,而不是所有情况,例如对于一般的np.ndarray
这种已经使用C进行了较大优化的数组,这种情况是有限的,
而且对于诸如一些for循环, 当循环次数不够多时,Cython的加速也是捉襟见肘。
而且由于引入了新的类型及变量会导致运行时间更长,
有时候速度与内存是不可兼得的,
比如要使用一个Bagging算法(统计中的BootStrap)需要初始化抽样数组,
这时如果利用生成器对于每一个样本逐个生成,并进行后续处理,
会在占用较小内存的情况下完成任务,但速度不佳,
但也可以选择先生成所有抽样下标样本,这样会消耗较多的内存,但速度应当是更快的。


举一个例子,下面的代码是用来产生Bagging样本的pure python代码:
def generate_bagging_sample_index(X, sample_num, sample_size):
ListRequire = []
for i in range(sample_num):
ListRequire.append(np.random.randint(X.shape[1], size = sample_size))


return np.array(ListRequire)


def generate_bagging_sample_array(X, sample_num, sample_size):
sample_indexs_array = generate_bagging_sample_index(X, sample_num, sample_size)
for sample_indexs in sample_indexs_array:
yield X[sample_indexs].copy()


def Bagging_Test_Simple_Func(X, factor_max_bound = 20, sample_num = 10, sample_size = 100, disp = False, Type = "forward_stepwise", itertimes = None):
factor_dict = dict()


def change_eigen_ratio_sample_order(eigen_ratio_sample):
array_require_T = np.empty(shape = eigen_ratio_sample.T.shape)
for i in range(eigen_ratio_sample.T.shape[0]):
array_require_T[i] = list(reversed(list(eigen_ratio_sample.T[i])))


return (array_require_T.T).copy()


def generate_forward_stepwise_eigen_ratio_sample(X_bagging_sample):
eigen_ratio_sample = None


for i in range(factor_max_bound ,sample_size):
eigen_v = np.abs(list(reversed(list(eigvalsh(np.dot(X_bagging_sample[ :i + 1], X_bagging_sample[ :i + 1].T)))))) ** 0.5


if disp:
print (eigen_v[:-1] / eigen_v[1:])[: factor_max_bound]
print np.argmax((eigen_v[:-1] / eigen_v[1:])[: factor_max_bound])


if type(eigen_ratio_sample) == type(None):
eigen_ratio_sample = np.array((eigen_v[:-1] / eigen_v[1:])[: factor_max_bound]).reshape(1, -1)
else:
eigen_ratio_sample = np.append(eigen_ratio_sample, np.array((eigen_v[:-1] / eigen_v[1:])[: factor_max_bound]).reshape(1, -1), axis = 0)


return eigen_ratio_sample




这些函数的作用仅仅是生成样本及计算特征值的比,但当考虑性能采用Cython进行改进
会得到一个非常不具有可读性的版本:
def generate_bagging_sample_index(np.ndarray X, int sample_num, int sample_size):
cdef np.ndarray ListRequire = np.empty(shape = (sample_num, sample_size)), random_list


cdef int i, j


for i in range(sample_num):
random_list = np.random.randint(X.shape[1], size = sample_size)
for j in range(sample_size):
ListRequire[<unsigned int>i][<unsigned int>j] = random_list[<unsigned int>j]


return ListRequire


def generate_bagging_sample_array(np.ndarray X, int sample_num, int sample_size):
cdef np.ndarray sample_indexs_array = generate_bagging_sample_index(X, sample_num, sample_size)
cdef int i


for i in range(sample_indexs_array.shape[0]):
yield X[np.array(sample_indexs_array[<unsigned int>i], dtype = np.int)].copy()


def Bagging_Test_Simple_C_Func(np.ndarray X, int factor_max_bound = 20, int sample_num = 10, int sample_size = 100, disp = False, Type = "forward_stepwise", int itertimes = 0):
factor_dict = dict()


def change_eigen_ratio_sample_order(eigen_ratio_sample):
cdef np.ndarray array_require_T = np.empty(shape = eigen_ratio_sample.T.shape)


cdef int i


for i in range(eigen_ratio_sample.T.shape[0]):
array_require_T[<unsigned int>i] = list(reversed(list(eigen_ratio_sample.T[<unsigned int>i])))


return (array_require_T.T).copy()


def generate_forward_stepwise_eigen_ratio_sample(X_bagging_sample):
cdef np.ndarray eigen_ratio_sample = np.empty(shape = (sample_size - factor_max_bound, factor_max_bound)), ratio_list, eigen_v


cdef int i, j


for i in range(factor_max_bound ,sample_size):
eigen_v = np.abs(list(reversed(list(eigvalsh(np.dot(X_bagging_sample[ :<unsigned int>i + 1], X_bagging_sample[ :<unsigned int>i + 1].T)))))) ** 0.5


ratio_list = np.array((eigen_v[:-1] / eigen_v[1:])[: factor_max_bound])
for j in range(ratio_list.shape[0]):
eigen_ratio_sample[<unsigned int>i - factor_max_bound][<unsigned int>j] = ratio_list[<unsigned int>j]


return eigen_ratio_sample




在测试这两个程序时会发现,Cython比前者慢(不会慢太多),这与直接将前者进行Cython编译
的结果是近乎相同的,当数据量不够大时后者完败。
所以Bagging的性能消耗本质仍是内存与速度的取舍,而非编译语言。








<think>好的,我现在要解决用户在IAR编译器中遇到的错误:“incomplete type is not allowed”。首先,我需要理解这个错误的含义和常见原因。根据我的知识库,这个错误常发生在代码中使用了未完全定义的类型,比如结构体或联合体声明了但未定义,或者前向声明了某个类型但没有提供完整的定义。 首先,我应该检查用户代码中是否有结构体或联合体的声明但没有定义的情况。比如,如果有一个结构体声明为`struct MyStruct;`,但没有后续的完整定义,那么在需要该结构体大小或成员的地方,编译器就会报这个错误。这时候,需要用户补全结构体的定义,包括成员变量。 其次,检查是否在头文件中只声明了类型而没有包含定义。例如,如果在头文件中使用前向声明,但在使用该类型的源文件中没有包含实际的定义头文件,这也会导致错误。此时,需要确保在使用类型的地方包含了正确的头文件,或者将前向声明替换为完整的定义。 另外,还要考虑typedef的问题。如果用户使用了typedef创建别名,但原始类型未完全定义,同样会引发错误。例如,`typedef struct MyStruct MyType;`之后,如果尝试使用MyType但MyStruct尚未定义,就会出错。需要确保在使用typedef之前,原始类型已经被完整定义。 此外,数组声明中的类型不完整也是一个常见原因。比如声明数组时,如果元素类型未完全定义,编译器无法确定数组的大小,导致错误。需要检查数组声明中的类型是否已经完整定义。 可能还有其他情况,比如在C和C++混合编程时,如果没有正确使用extern "C",或者在头文件中遗漏了必要的包含,也可能导致类型不完整。需要用户检查这些方面。 接下来,我需要将这些可能的原因整理成清晰的解决步骤,并给出具体的代码示例,帮助用户理解如何修改。同时,根据用户提供的引用内容,虽然引用[1]和引用[2]是关于其他错误的,但用户可能希望看到类似的结构,即分点说明解决方案,并引用相关资源。 最后,生成相关问题,帮助用户进一步了解可能相关的编译错误,比如类型未定义、前向声明问题等。这样用户可以有更全面的认识,预防其他类似错误的发生。</think>### IAR编译器错误'incomplete type is not allowed'解决方案 该错误表示代码中使用了**未完全定义的类型**,编译器无法确定其内存布局或成员信息。以下是具体原因及解决方法: #### 1. 结构体/联合体未定义完整 若声明了结构体但未定义成员,在实例化时会报错: ```c struct MyStruct; // 前向声明不完整 struct MyStruct var; // 错误:使用未完成类型 ``` **解决方案**:补全类型定义 ```c struct MyStruct { int id; char name[20]; }; ``` #### 2. 头文件包含缺失 当跨文件使用类型时,需确保定义可见: ```c // file.h struct Data; // 前向声明 // file.c struct Data { // 实际定义 int value; }; ``` **解决方案**:在使用该类型的文件中包含定义头文件 ```c #include "file.c" // 包含实际定义 ``` #### 3. typedef别名问题 使用typedef时原始类型必须完整: ```c typedef struct Node NodeT; // 前向声明 NodeT* ptr; // 允许指针声明 NodeT instance; // 错误:不完整类型 ``` **解决方案**:先完成类型定义再typedef ```c struct Node { int data; struct Node* next; }; typedef struct Node NodeT; ``` #### 4. 数组声明不完整 数组元素类型必须完全定义: ```c struct Element; struct Element arr[10]; // 错误:元素类型未定义 ``` **解决方案**: ```c struct Element { int type; float value; }; struct Element arr[10]; // 合法 ``` #### 调试建议 1. 在IAR工程中搜索错误行号定位问题代码 2. 使用Go to Definition功能追踪类型定义 3. 检查所有头文件包含链 4. 确认没有循环依赖的头文件 编译器需要知道类型的完整信息才能: - 计算sizeof大小 - 分配内存空间 - 访问成员变量 - 进行类型对齐 [^1]: 类似类型转换错误可参考浮点转整型的类型适配问题。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值