[英]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.