簡體   English   中英

c malloc 數組指針在cython中返回

[英]c malloc array pointer return in cython

如何有效地將 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):

到目前為止,其他排列均未成功。 c 和 cython 代碼版本比 Numby/pylab randn 版本快 5 倍,如果我能找到一種方法返回指向大型 10^6 到 10^10 雙復數數組的指針的話。

Numpy C API

你的問題與這篇文章類似。

您可以使用下面的函數將C指針傳遞給Numpy數組。 當Numpy陣列被回收時,內存將自動釋放。 如果你想要指針釋放指針,你不應該設置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 Typed Memoryviews

當然,你也可以使用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數組。 然而,這不會自動釋放內存,你必須自己釋放內存,否則會導致內存泄漏!

另一個選項(除了頂部答案中的兩個選項: PyArray_SimpleNewFromData並且只返回類型化的內存視圖而不處理內存)是使用cython.view.array class

這是一個相當低級的 class,可用於包裝現有的 memory。它具有一個屬性callback_free_data ,您可以在其中設置 function 以在銷毀時調用,以便它釋放 memory(此處的示例代碼是從文檔中復制的) :

cdef view.array my_array = view.array(..., mode="fortran", allocate_buffer=False)
my_array.data = <char *> my_data_pointer

# define a function that can deallocate the data (if needed)
my_array.callback_free_data = free

它公開了緩沖區協議,以便您可以對其進行索引,將其與類型化的內存視圖一起使用,或者使用 np.asarray 用np.asarray數組(不復制)包裝它。 后一個功能可能比PyArray_SimpleNewFromData更容易使用。

我認為最好的方法是將通過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

對於使用C-11標准的gcc 5+(gcc -std = gnu11 ...),多維malloc和calloc數組的語法已經發生了顯着變化。

一個main()過程,用於為n = 1024創建一個2-D,雙,復數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一起使用。 我希望很快就能測試一下。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM