簡體   English   中英

將 numpy 數組的切片視圖傳遞給 cython - 復制在哪里發生?

[英]passing sliced view of numpy array to cython - where is the copy happening?

在下面的代碼中,我對數組 X 進行切片,從而在 X 上創建一個名為X_cut的視圖。 然后我在切片上使用 cython 內存視圖,並將其作為一維數組傳遞給線性訪問內存的 ac 函數。

我可以確定傳遞給 C 代碼的指針實際上是指 6x6 線性化矩陣嗎?

如果是這樣,復制操作在哪里發生? 它在X_cut.ravel()嗎?

%%cython

import numpy as np

cdef extern from "/some/path/to/get_5_5.c":
    long get5_5(long* arr, int M, int N)

M = 6
N = 8

X = np.arange(M*N).reshape(M, N)

N_cut = 6
X_cut = X[:, :N_cut]

cdef long[::1] arr = X_cut.ravel()

print(get5_5(&arr[0], M, N_cut))

/some/path/to/get_5_5.c

long get5_5(long* arr, int M, int N) {
  return arr[5*N + 5];
}

Cython 的類型化內存視圖使用緩沖區協議來訪問數據,這意味着它們與數據復制無關。

從理論上講,導出器可以決定在通過緩沖區協議公開數據時復制數據。 但是,通常使用Buffer-Protocol 是為了避免內存復制,因此復制不是正常情況。 這意味着,您不能 100% 確定,將類型化內存視圖綁定到導出緩沖區的對象時不會發生復制 - 您必須知道導出器的實現,但復制的情況非常罕見。 這不是這里發生的事情。

復制必須發生,當X_cut.ravel()被調用時 - 結果內存必須是連續的,但X_cut的底層內存不是(參見X_cut.flags ),因為它仍然與X共享內存並切斷最后一個元素每行都會導致內存中的“漏洞”。

以下是內存布局(為簡單起見,M=2、N=3、N_cut=2):

  X:               X00,X01,X02,X10,X11,X12
  X_cut:           X00,X01,...,X10,X11        # ... - hole in memory, no copying
  X_cut.ravel():   X00,X01,X10,X11            # memory contiguous, copying needed

它讓你在哪里? 您要么必須接受內存的復制,要么擴展get5_5的接口,因此您還可以傳遞非連續的內存布局 - 與 Buffer-Protocol 相似。

例如,要X_cut不復制的情況下傳遞X_cut ,您不僅需要(僅)指定形狀,還需要指定沿維度的步幅,即

#only stride along the the first dimension is needed:
cdef long get5_5(long* arr, int stride_row, int stride_col):
     return arr[stride_row*5+5]

問題是,如何在不復制的情況下從X_cut獲取指針long* arr

一種可能性是使用 2D 內存視圖,我會選擇此選項):

cdef long[:,::1] arr = X_cut
get5_5(&arr[0][0], M, N) # and not M, N_cut

另一種方法是使用np.reshape(-1) ,它創建一個新的一維視圖並且並不總是復制數據(與np.ravel()不同):

cdef long[::1] arr = X.reshape(-1) # X_cut.reshape(-1) would copy the data!
get5_5(&arr[0], M, N)  # and not M, N_cut

暫無
暫無

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

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