python调⽤C函数时的数组传递
python调⽤C函数时的数组传递
2019-4-5
引⾔:最近需要对⼀个算法进⾏并⾏加速,最初使⽤python实现的,也尝试了⽤python中的多线程进⾏加速,后来才发现,python中
的threading受制于GIL,同时只能使⽤⼀个核进⾏运算,所以搞了半天最后发现多线程和⾮并⾏算法在运⾏时间上⽆差别。当然我也尝试
了multiprocessing模块,但我那个算法不适合⽤多进程的⽅法加速,反⽽会导致程序运⾏时间变长,所以我就只好退⽽求其次,需要加速的部分⽤C语⾔重写,并通过C的多线程来进⾏加速。所以就涉及到了python调⽤C函数的问题。因为需要将python中的numpy数组传递到C 函数中,为了实现这⼀部分也花了两个晚上才折腾明⽩,所以记录下来,我⾃⼰也是刚学这⼀部分,可能⽆法写的特别精致到位,只是把我⾃⼰觉得有⽤的部分记录。
1. ctypes
ctypes是python提供的⼀个⽤来调⽤C函数的模块。在⽹上看到很多⼈都建议⽤ctypes的⽅法在python中调⽤C的动态链接库。具体关于ctypes的介绍可以去官⽹上看⼀下。
from ctypes import*
2. C函数
2.1 编写C函数
由于ctypes的功劳,c函数部分按照正常写c的⽅法写即可。下⾯是我测试时写的⼀个c⽂件:
//ctype_test.c
#include<stdio.h>
void onedemiarr(const int* a,int n,int* b){
puts("onedemiarr starts!\n");
int i;
for(i =0; i < n; i++){
b[i]= a[i]*2;
}
puts("onedemiarr ends!");
return;
}
void twodemiarr(const int(*a)[3],int m,int n,int(*b)[3]){
puts("twodemiarr starts!\n");
int i, j;
for(i =0; i < m; i++){
for(j =0; j < n; j++){
python 定义数组b[i][j]= a[i][j]*2;
}
}
puts("twodemiarr ends!\n");
return;
}
函数onedemiarr, twodemiarr均为将数组a的内容乘以2放⼊数组b中。
在这⾥想说的是,写完C代码后,⼀定要都测试⼀下⾃⼰的C函数写的是否正确,是否可以通过main函数来正常调⽤,不然不经测试即在python中使⽤,很可能出错了也没办法发现是C函数本⾝的错(我⾃⼰就是这么被⾃⼰坑过来的)。
2.2 编译动态库
使⽤gcc命令将c函数编译为动态链接库,因为我是在windows下写的,所以编译成.dll格式,如果是linux下就是.so格式了。
gcc -shared ctype_test.c -o ctest.dll //-shared说明这是⼀个动态库
需要注意的是,⽣成的动态链接库如果是32位的(根据电脑上的MinGW位数⽽定),则只能被32位的python调⽤,如果⽤64位的python调⽤32位的动态链接库会报错。
3. python部分
当我们编译好动态链接库后,主要的⼯作就在python部分了。python中需要做的事情有:引⼊动态链接库,定义参数,申明动态链接库中函数的参数格式,调⽤C函数。
#ctype_test.py
from ctypes import*
import numpy as np
peslib as npct
if __name__ =='__main__':
arr_1 = np.array([1,2,3,4], dtype = np.int)
arr_2 = np.ndarray((4,), dtype = np.int)
arr_3 = np.array([[1,2,3],[4,5,6]], dtype = np.int)
arr_4 = np.ndarray((2,3), dtype = np.int)
lib = npct.load_library("ctest",".")#引⼊动态链接库,load_library的⽤法可参考官⽹⽂档
'''
申明函数onedemiarr, twodemiarr的传⼊参数类型;ndpointer为peslib扩展库中提供的函数,
可将numpy数组转为指针形式被C函数识别, 其中ndim表⽰数组维数,还有⼀个shape参数(可选)表⽰数组格式,
flags = "C_CONTIGUOUS" 表⽰是和C语⾔相似的数组存放⽅式。
'''
c_int, npct.ndpointer(dtype = np.int, ndim =1, flags="C_CONTIGUOUS")]
lib.twodemiarr.argtypes =[npct.ndpointer(dtype = np.int, ndim =2, shape =(2,3), flags="C_CONTIGUOUS"),
c_int, c_int, npct.ndpointer(dtype = np.int, ndim =2, shape =(2,3), flags="C_CONTIGUOUS")]
print(arr_1,arr_2)#将数组内容打印出来,就会发现此时arr_2数组的内容已经被改变。
print("**----------------**")
lib.twodemiarr(arr_3, c_int(2), c_int(3), arr_4)
print(arr_3,"\n",arr_4)
确认python代码⽆误了,就可以执⾏python程序了。
python ctype_test.py
以上内容均已测试⽆误,测试平台为:Windows10, MinGW32位,python32位。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论