python - 使用 ctypes 从 C 结构数组到 NumPy 数组的高效转换
问题描述
在我试图将 C++ DLL 与. 由于繁重的 SO 浏览,我现在使用 ctypes 成功调用了我对 DLL 感兴趣的函数。我现在面临在 Python 中使用结构数组的结果的问题。Cython
ctypes
这个C函数如下:
void myfun(
double a,
//...more double parameters
int max_iter,
int * nb_iter,
myStruct * res_arr,
bool * ok
);
定义myStruct
如下:
typedef struct {
double dat;
int k;
int m;
// ... more int
double b;
double v;
//...more double
} myStruct;
我通过以下 Python 代码调用此函数:
import ctypes
lib = ctypes.CDLL('PATH_TO_DLL\\lib.dll')
myFunPy = getattr(lib,"?myFun@@YANNNNN_BUNCH_OF_Ns_NNNHPEAHPEAUmyStruct@@PEA_N@Z") # name found through dumpbin.exe (due to C++)
class myStruct(ctypes.Structure):
_fields_ = [("k", ctypes.c_int),
("m", ctypes.c_int),
#...more int parameters
("b", ctypes.c_double),
("v", ctypes.c_double)
#...more double parameters
]
myFunPy.argtypes = [ctypes.c_double,
// ... more double parameters
ctypes.c_int,
ctypes.POINTER(ctypes.c_int),
ctypes.POINTER(myStruct),
ctypes.POINTER(ctypes.c_bool)]
myFunPy.restype = ctypes.c_void_p
max_iter = 10000
a = ctypes.c_double(0.1)
// ... more double parameters definitions
nb_iter = ctypes.c_int(0) # value doesn't matter, it is initialized in myFun
ok = ctypes.c_bool(True)
res_arr = (myStruct * max_iter)()
myFunPy(a, ..., max_iter, ctypes.byref(nb_iter), res_arr, ctypes.byref(ok))
现在myFun
修改res_arr
which 是一个结构数组,从上面的代码可以看出。正是
<__main__.myStruct_Array_10000 at 0x97966c8>)
在上面显示的代码之后,但我无法理解如何将其转换为 NumPy 数组以供将来有效使用。
当然,我可以使用此处for field, _ in struct._fields_
所示的内容进行 for 循环,但这不是重点,因为我使用 DLL 使我的计算更快(我真的看到了执行时间的差异)。范围从 200 kb 到 1 Mb,有数万行和几十列,所以我确信有一种方法可以不用循环遍历所有内容,但我不知道该怎么做太好了。res_arr
似乎如果它不是一个结构数组,它会更容易。有一些 SO问题(也在这里,这里,这里和这里)接近这个主题,但它要么只是转换一个结构,只是一个数组,或者是一些接近但从不完全像我的东西,我没有成功 调整这些解决方案,所以也许有办法以此为基础回答,但无论如何我都在听。
解决方案
我们有几乎相同的问题,但就我而言,我使用的是 CUDA DLL,所以我的编译器是nvcc
. 但我相信这也可以通过普通的g++
编译器来完成。无论如何,这里是我为了将结构数组从我的 CPP 文件转换为可用的 Python 列表/数组而执行的步骤。我不会浏览你的代码;相反,我只会给你一个可以在这里找到的例子:https ://github.com/jcbacong/python-cpp.git
但重要的步骤总结如下:
extern "C"
使用包含函数声明的必要头文件创建一个 .cpp 文件。在我的 .cpp 文件中,我返回了一个结构数组,而不是返回一个void
.使用您的编译器创建一个 .dll 文件。同样,在我的情况下,它是
nvcc
. 我通过我的 github 帐户链接的示例代码是使用nvcc
.在您的 .py 文件中:
3.1 创建一个 Python 类,
ctypes.Structure
以便复制 .cpp/.h 文件中的结构定义。3.2 使用 . 初始化您的输入/输出
argtype/restype
。由于我的 .cpp 函数返回一个结构数组,因此由 .cpprestype
给出ctypes.Pointer(<your Python Class(ctypes.Structure)>)
。3.3 我将所有输入转换为可读的 ctypes。在我的 .py 文件中调用函数后,
_results
可以使用 ( ) 将生成的结构数组(在示例中)转换为 Python 列表results = _results[:ARRAY_SIZE]
。
我希望这有帮助!!
推荐阅读
- python - Python Dataframe颜色在单元格中使用字典
- git - Gitlab:如何将私有存储库从服务器 A 分叉到服务器 B?
- java - 将 JButton 数组添加到 JPanel(按钮不可见)
- java - Lucene 禁止子类 Query 解析 Query
- corda - 在 Corda Enterprise 中,没有为架构错误定义迁移
- spring - Spring Boot WAR 生成器
- python - 带双引号的熊猫数据
- windows - 适用于 Windows 的 Jenkins JEP-200 解决方法
- django - Django 中的 AD 身份验证连接到 LDAP 服务器但身份验证失败?
- jquery - 将href添加到jQuery中的类