2017-07-12 51 views
2

以下代碼:爲什麼大numpy的陣列64字節對齊的但不是較小的

prev=[] 
addresses=[] 
for i in range(10000): 
    a = np.ones(x).astype(np.float32) 
    prev.append(a) 
    address = a.__array_interface__['data'][0] 
    assert(address % 64 == 0) 
    assert((address not in addresses)) 
    addresses.append(address) 

不會用於建議的X> 252值提高的assertionError,數組大於253,(或大於505大當使用float16時)與小數組的排列方式不同。這是什麼原因?

我在OSX(英特爾(R)酷睿(TM)i7-6920HQ CPU @ 2.90GHz)運行numpy 1.12.1

+0

難道這只是純粹的機會嗎?如果你打印而不是斷言會發生什麼? –

+0

@MadPhysicist - 沒有機會少於一萬分之一(這就是外部循環的目的) –

+0

但是,當一個斷言失敗的時候,你會跳出循環。繼續看看會發生什麼。 –

回答

1

這裏是我的猜測:使用對齊的內存通常涉及分配較大的塊,然後釋放在對齊邊界之前分配的前端字節。

這對於大型陣列來說並不重要,但對於小陣列來說,引入的碎片和開銷可能超過了優勢。

+0

有什麼好處? –

+1

緩存行在對齊的塊中讀取;所以對齊陣列比非對齊陣列需要更少的緩存行讀取和存儲空間。此外,我認爲,內存映射僅適用於大多數平臺上的對齊內存塊。也可能有其他原因。 –

2

您的測試循環並不完全符合您的期望。由於一次只有一個數組在內存中存在,所以很可能 - 確實可能 - 新數據將被分配到與剛剛釋放的內存地址相同的內存地址。您必須執行一些操作,例如將數組附加到列表中(從而使它們全部同時存在於內存中)來實際測試10000個不同的分配。

但是,我可以輕易相信你會看到一個真正的效果,因爲內存分配器根據所分配塊的大小使用不同的策略是完全合理的。例如,在某些時候,分配器可能會停止嘗試使用已有的內存,並直接從操作系統請求整個內存頁。一旦達到了這個閾值,你會發現所有的東西都在一個比64更高的2次冪邊界上 - 也許是4096.你似乎在1024字節(包括開銷)上達到了一些中間閾值,這可能是有趣的測試128/256/512/1024字節對齊。

+0

您在地址重用方面做得很好,我修改了我的問題中的代碼以排除這種可能性。 –

+0

我做了你所建議的關於嘗試不同的路線,它變得更有趣 - 在512有另一個對齊,然後是更大的數組1024。 –

相關問題