我正在尝试尽可能高效地将 double 组从 C 库发送到 Python。 与此库通信的代码是由另一家公司创建的(它包括许多方法、异常等),但是这个特定函数创建一个列表并从 C 中的每个项目中插入一个 Python 对象数组,如果你关心速度,这是非常低效的。
下面是编译用于创建 python 模块的 C 代码片段:
static PyObject* foo(PyObject* self, PyObject* args) {
double *val = 0;
//more variables
//Note that this uses the Python C API PyArg_ParseTuple to handle the parameters
if (! PyArg_ParseTuple(args, "ii", &listID, &size)) {
//send exception
}
//some code here that allocates an array to hold "val" and calls the C library
PyList_New(size);
for(i = 0; i < size; i++) {
PyList_SET_ITEM(retData, i, Py_BuildValue("d", val[i]));
}
//free resources, return the Python object
}
我发现 Python array可能有用,还有适合多进程的额外好处。
如果Python数组按照我的想象工作,我可以在Python中分配数组,然后C库就填充它
from cpython cimport array
import array
from dalibrary import dafunction
cdef array.array a = array.array('d', [])
array.resize(a, 1000)
dafunction(array, 1000) # In a very "C" style, the array would be filled with values
print(array)
问题是我没有找到有关使用 Python 数组所需的 C 代码的文档。至少不使用Python C API。
注意:我知道 ctypes,但这意味着重写整个模块,如果可能的话,我宁愿不这样做(但缺乏文档可能会驱使我这样做)
似乎有人已经问过类似的问题 here ,但仍未解决
结果:
我设法执行了我想要的操作(正如您可能在其中一个答案中看到的那样),甚至对数组(多进程数组)使用多线程,但令我惊讶的是,它实际上比使用据说效率低下的方法要慢一些(但是健壮的)IPC 方法,例如带有 Python 列表的队列。
由于使用Python API很困难,而且它给我带来的改进为零,我认为对社区来说最好的答案是使用ctypes的建议。我会保留我的答案以供引用。也许发送大量内存的人可能会从中受益。
最佳答案
要将数据从 C 转换为 Python,需要做很多事情。首先你应该决定谁来处理内存。生成数组的是 C 代码还是 Python?如果数组在很多地方共享,并且在 Python 不知情的情况下在 C 端被删除,Python 将崩溃。或相反亦然。
因此复制数组可能不是一个坏主意。
话虽如此,您可以编写一个简单的 C 函数
struct Array {
int size;
int* data;
}
Array get_my_array() {
//...
return {size, val};
}
将其编译为动态库 (my_lib.so
) 并使用 Ctypes 对其进行包装(它是用于访问外部函数的标准 Python 库)。
您需要描述Array
返回类型:
from ctypes import Structure, POINTER, c_int, CDLL, find_library, pointer
class Array(Structure):
__fields__ = [("size", c_int), ("data", POINTER(c_int))]
my_lib = CDLL(find_library("my_lib"))
my_lib.get_my_array.restype = Array
现在您可以获取数组并访问其数据和大小(并手动保护自己免受越界访问)。
例如,您也可以将其传递给 Numpy。幸运的是,这里的答案中有一个相当完整的示例How to create n-dim numpy array from a pointer? 仔细阅读,别忘了清理内存。
请注意,您也可以以相反的方式进行操作。如果您在 Python 中知道要创建的数组的大小并且只需要 C 代码来填充它,则可以在 CTypes 中创建它,并将其传递给接受指针和大小的 C 函数。
ArrayType = c_int * size
array = ArrayType()
my_lib.populate_array(pointer(array), size) # left as an exercise
Ctypes 非常方便,当您了解 C 语言时,它会变得很有意义。
关于python - 如何使用 Python C API 在已编译的 C 模块中实现 Python 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59901282/