【问题标题】:c malloc array pointer return in cythonc malloc数组指针在cython中返回
【发布时间】:2014-09-25 23:11:34
【问题描述】:

如何高效地将 cython 中的 malloc 数组指针(或 numpy 数组指针)返回给 python3。

只要我不返回数组指针,cython 代码就可以完美运行

我想要:

def double complex* randn_zig(int n):
  ...
  r = malloc(n*n*sizeof(double complex))
  ...
  return r

等效的 c11 (gcc 11) 是:

double complex* randn_zig(int n){

    r = malloc(n*n*sizeof(double complex))

    return r
}

我试过了 <double complex*> randn_zig(int n):

randn_zig(<double complex*> r, int n):

和其他排列到目前为止没有成功。如果我能找到一种方法来返回指向大型 10^6 到 10^10 双复数数组的指针,c 和 cython 代码版本的速度是 Numby/pylab randn 版本的 5 倍。

【问题讨论】:

  • 当你试图调用这个函数时,你能提供更多的代码吗?您会遇到哪些错误?
  • 没有与指针等效的python,所以它不是你想要返回的指针,它是对已分配内存块的一些引用(即,一些具有指向指针的python对象) .您选择哪种 python 对象取决于您打算如何处理指针/内存块。

标签: python c arrays numpy cython


【解决方案1】:

Numpy C API

您的问题类似于this post

您可以使用下面的函数将 C 指针传递给 Numpy 数组。当 Numpy 数组被回收时,内存将被自动释放。如果你想释放指针mamully,你不应该设置NPY_OWNDATA标志。

import numpy as np
cimport numpy as np

cdef pointer_to_numpy_array_complex128(void * ptr, np.npy_intp size):
    '''Convert c pointer to numpy array.
    The memory will be freed as soon as the ndarray is deallocated.
    '''
    cdef extern from "numpy/arrayobject.h":
        void PyArray_ENABLEFLAGS(np.ndarray arr, int flags)
    cdef np.ndarray[np.complex128, ndim=1] arr = \
            np.PyArray_SimpleNewFromData(1, &size, np.NPY_COMPLEX128, ptr)
    PyArray_ENABLEFLAGS(arr, np.NPY_OWNDATA)
    return arr

供参考:

Cython 类型化内存视图

当然,你也可以使用cython memoryview

import numpy as np
cimport numpy as np

cdef np.complex128_t[:,:] view = <np.complex128_t[:n,:n]> c_pointer
numpy_arr = np.asarray(view)

上面的代码会将 C 指针转移到一个 numpy 数组。 但是,这不会自动释放内存,您必须自己释放内存,否则会导致内存泄漏!

【讨论】:

  • 1. Syrtis 谢谢,很快就会尝试。我现在真的需要为一个项目解决这个问题。请参阅下面的评论。
【解决方案2】:

我认为最好的方法是通过 NumPy 将在 Python 中创建的现有数组的指针传递给 Cython,否则您似乎必须将 malloc 创建的数组的内容复制到另一个数组,就像在这个玩具示例:

import numpy as np
cimport numpy as np

from libc.stdlib cimport malloc, free

def main():
  cdef int i, n=40
  cdef double complex *r
  cdef np.ndarray[np.complex128_t, ndim=1] a
  a = np.zeros(n*n, dtype=np.complex128)
  r = <double complex *>malloc(n*n*sizeof(double complex))
  for i in range(n*n):
      r[i] = 1.
  for i in range(n*n):
      a[i] = r[i]
  free(r)
  return a

【讨论】:

  • 我一直忙于其他项目,现在回来解决这个问题。谢谢。无论如何,python 3.4 和 numpy 似乎包含 Meresenne 素数生成器,我假设它是 dsfmt(),Ubuntu 15.10 中的默认值。我还没有查看 ppython3.4 的 Python 源代码,但 3.2 没有。我不确定他们是否有用于 randn() 的 Ziggurat 或 Leva 算法。我需要看看。如果需要,我将实施一个。 73
【解决方案3】:

对于使用 C-11 标准 (gcc -std=gnu11 ...) 的 gcc 5+,多维 malloc 和 calloc 数组的语法发生了显着变化。

现在是一个 main() 过程,用于为 n = 1024 创建一个二维、双精度、复数 calloc 数组 r[n][n]:

long n = 1024;
complex double (*r)[n] = calloc(n, sizeof *r);

使用指向此 calloc 数组 r[n][n] 的指针的高斯随机数生成器 randn_box_muller() 的示例是:

inline static void randn_box_muller(long n, complex double r[][n])
{
    long i, j; 
    register double x, y;

    for(i = 0; i < n; i++){
        for(j = 0; j < n; j++){  
            x = 2.*M_PI*dsfmt_genrand_close_open(&dsfmt);
            y = sqrt(-2.*log(dsfmt_genrand_close_open(&dsfmt)));
            r[i][j] = (cos(x) + I*sin(x))*y;
        }
     }
     return;
}

这种相对较新的 calloc 分配语法有点奇怪。它适用于 1、2 甚至 n 维 calloc 和 malloc 数组。希望这也可以与 Python3 一起使用。我希望很快能对此进行测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    • 2020-09-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多