Python C API读取列表,分配内存和全局变量

时间:2014-05-03 09:19:13

标签: python c arrays memory-management python-c-api

我正在编写一个模块以优化操作,但我有几个问题。

第一

我需要从python到C读取一个数组(列表列表),我这样做了:

long i_k;
for (int k = 0; k < n; k++) {
  PyObject *first = PyList_GetItem(streamMatrixObj, k);
  for (int i = 0; i < n; i++) {
    PyObject *second = PyList_GetItem(first, i);
    i_k = PyLong_AsLong(second);
    f[k][i] = i_k;
  }
} 

矩阵始终为n x n。有没有更好的方法来读取和存储列表列表到C数组?

第二

我正在为C数组分配内存,如下所示:

void **createMatrix(uint rows, uint cols) {

  long **matrix;

  const size_t row_pointers_bytes = rows * sizeof(*matrix);
  const size_t row_elements_bytes = cols * sizeof(**matrix);
  matrix = PyObject_Malloc(row_pointers_bytes + rows * row_elements_bytes);

  if (!matrix) {
    PyErr_NoMemory();
    return NULL;
  }

  size_t i = 0;
  long *data = matrix + rows;
  for (i = 0; i < rows; i++)
    matrix[i] = data + i * cols;

  return matrix;
}

我应该使用PyMem_Malloc还是PyObject_Malloc?,我在这个问题中看到了解释

Is there any reason to use malloc over PyMem_Malloc?

但仍然不知道调用什么是合适的函数。

第三

这个模块的方法将被多次调用,因此,我想将C数组保留在内存中,以避免每次都重新创建数组。例如,从python我会调用方法myModule.deltaC(1,2,[1,2,3]),该调用将对矩阵执行一些操作。

我可以在使用deltaC函数之前初始化数组,例如myModule.initMatrix([[1,2,3],[1,2,3], [1,2,3]])并将其保留在内存中直到程序完成?那么C数组需要是模块中的全局变量吗?

更新

我尝试在module.initMatrix的全局变量中初始化C数组,但是当调用module.delta时,我在访问C数组时得到了一个SegFault,所以我想这是不可能的或者我错过了什么。

有没有办法检测python程序何时完成以调用PyObject_free(array)来释放为C数组分配的内存?

1 个答案:

答案 0 :(得分:1)

第一:几乎应该如何做。

第二:我理解你应该PyMem_Malloc / PyMem_Free在这里。 PyObject_Malloc / PyObject_Free用于分配Python对象,并针对许多较小的对象进行了优化。但是,除非您分配大量内存或进行大量分配,否则无关紧要。

第三&amp;第四:您可以使用Capsules API来存储C结构并将它们传递给API函数。您可以让初始化函数(initMatrix)返回包含矩阵的包,并将此包传递给其他函数(例如deltaC),而不是存储全局矩阵。当矩阵不再被引用时,它将被自动销毁。

如果您不打算存储除矩阵之外的任何内容,则可能的替代方法是使用numpy数组。这些数组可以通过C中的numpy C API作为矩阵直接访问。这样可以节省调用Python C API函数来检索矩阵的每个元素,自己分配内存或者在销毁时解除分配的需要。