2010-02-06 47 views
20

在Python中初始化和訪問大型數組元素的有效方法是什麼?1億個零的高效Python數組?

我想在Python中創建一個數組,其中有1億個條目,無符號4字節整數,初始化爲零。我想要快速的數組訪問,最好是連續的內存。

奇怪的是,NumPy陣列似乎表現非常慢。有我可以嘗試的替代方案嗎?

array.array模塊,但我沒有看到一種方法來有效地分配1億塊條目。

迴應評論:

  • 我不能用一個稀疏數組。這個算法對於這個算法來說太慢了,因爲這個陣列變得非常快速。
  • 我知道Python被解釋,但肯定有辦法做快速數組操作?
  • 我做了一些分析,並用NumPy每秒獲得大約160K個數組訪問(按索引查找或更新元素)。這似乎很慢。
+1

您正在談論數百MB的數組,解釋性語言......對於您來說,速度有多慢? – 2010-02-06 20:49:41

+4

你的數組會稀疏嗎?爲實際使用的條目分配內存可能會更好。 – 2010-02-06 20:51:07

+3

您可能想詳細說明您想如何處理它。 「高效」本身沒有意義。 – balpha 2010-02-06 20:51:19

回答

28

我做了一些分析,結果完全違反直覺。 對於簡單的數組訪問操作,numpy和array.array比原生Python數組慢10倍。

注意,對於數組訪問,我做形式的操作:

a[i] += 1 

概況:

  • [0] * 20000000

    • 訪問:2.3M /秒
    • 初始化:0.8s
  • numpy.zeros(形狀=(20000000),D型細胞= numpy.int32)

    • 訪問:160K /秒
    • 初始化:0.2S
  • 陣列。陣列( 'L',[0] * 20000000)

    • 訪問:175K /秒
    • 初始化:2.0S
  • array.array( 'L',(0,i的範圍(20000000)))

    • 訪問:175K /秒,據推測,基於該配置文件其他array.array
    • 初始化:6.7s
+7

這是因爲索引一個Python列表是一個非常快的操作:它只是獲取已經在內部數組中的對象。 'array.array'和'numpy.array'對象不包含Python對象,因此存儲在數組中的實際數據類型需要在訪問時轉換。這是大大降低內存使用量和實際連續數據塊的代價。 – 2010-02-06 21:21:40

+8

@Joseph:+1實際測量它,而不是依靠互聯網上一羣匿名隨機人員的意見點擊箭頭。 ;) – 2010-02-06 21:32:29

+0

@Thomas:你能否詳細說明我如何在numpy中更快地執行增量?也許我可以避免使用Python對象? – 2010-02-06 21:40:18

7

試試這個:

x = [0] * 100000000 

它只需幾秒鐘,我的機器上執行,並獲得接近即時。

+1

這是我能想到的最好的方式。 – 2010-02-06 21:02:02

+0

奇怪的是,這種方法的初始化和訪問速度最快。 – 2010-02-06 21:18:27

+0

Ragnar Lodbrok提出的方法 – 2017-05-01 06:49:21

3

你不可能找到比numpyarray更快的東西。陣列本身的執行效率與其在C中一樣高效(基本上與array.array相同,只是用處更大)。

如果要加快代碼速度,您必須通過這樣做來做到這一點。即使數組被有效地實現,從Python代碼訪問它也有一定的開銷;例如,索引數組會產生整數對象,這些對象必須在運行中創建。 numpy提供了許多在C語言中高效實現的操作,但是沒有看到實際的代碼不能很好地執行,並且你很難提出任何具體的建議。

+0

看看我的答案。事實證明,numpy讓我訪問非常緩慢。 – 2010-02-06 21:19:06

1

除了其他優秀的解決方案之外,另一種方法是使用dict而不是數組(存在的元素不爲零,否則爲零)。查找時間是O(1)。

您可能還會檢查您的應用程序是否駐留在RAM中,而不是交換。它只有381 MB,但系統可能因爲任何原因而無法完成所有操作。

但是也有一些非常快速的稀疏矩陣(SciPyndsparse)。他們在低級C中完成,也可能是好的。

+0

我不能使用字典,因爲它會使用太多的內存。 – 2010-02-06 21:18:05

0

NumPy是大型固定大小同類陣列的適當工具。雖然全陣列操作通常可以以類似於C或Fortran的速度進行,但在Python中訪問單個元素的速度並不會很快。如果你需要快速地對數百萬和數百萬個元素進行操作,那麼只有很多你可以從Python中跳出來。

你正在實施什麼樣的算法?你怎麼知道使用稀疏數組太慢,如果你還沒有嘗試過?「高效」是什麼意思?你想快速初始化?這是你的代碼的瓶頸?

+0

我知道稀疏數組會太慢,因爲數組變得非常快。 – 2010-02-06 21:41:31

3

用於快速創建,使用陣列模塊。

使用陣列模塊更快的創造〜5倍,但對訪問元素相比正常名單大約兩倍的速度慢:

# Create array 
python -m timeit -s "from array import array" "a = array('I', '\x00' 
* 100000000)" 
10 loops, best of 3: 204 msec per loop 

# Access array 
python -m timeit -s "from array import array; a = array('I', '\x00' 
* 100000000)" "a[4975563]" 
10000000 loops, best of 3: 0.0902 usec per loop 

# Create list 
python -m timeit "a = [0] * 100000000" 
10 loops, best of 3: 949 msec per loop 

# Access list 
python -m timeit -s "a = [0] * 100000000" "a[4975563]" 
10000000 loops, best of 3: 0.0417 usec per loop 
13

只是一個提醒Python的整數是如何工作的:如果分配列表說

a = [0] * K 

你需要的名單(sizeof(PyListObject) + K * sizeof(PyObject*))和單整數對象0這些內存。只要列表中的數字保持在Python用於緩存的幻數V以下,就沒問題,因爲它們是共享的,即任何指向數字n < V的名稱都指向完全相同的對象。您可以使用下面的代碼片段找到該值:

>>> i = 0 
>>> j = 0 
>>> while i is j: 
... i += 1 
... j += 1 
>>> i # on my system! 
257 

這意味着,一旦罪名上面去這個數字,你需要的內存是sizeof(PyListObject) + K * sizeof(PyObject*) + d * sizeof(PyIntObject),其中d < K高於V (== 256)整數數量。在64位系統上,sizeof(PyIntObject) == 24sizeof(PyObject*) == 8,即最壞情況的存儲器消耗是3,200,000,000字節。如Thomas Wouters所說,在初始化之後,內存消耗是不變的,但是您支付透明地創建的包裝對象。可能,您應該考慮通過使用Cythonscipy.weave將更新代碼(訪問並增加陣列中的位置)轉換爲C代碼。

0

我只是簡單地創建你自己的數據類型,它不會初始化任何值。

如果您想讀取尚未初始化的索引位置,則返回零。不過,不要初始化任何存儲。

如果您想讀取已經初始化的索引位置,只需返回該值即可。

如果要寫入尚未初始化的索引位置,請對其進行初始化並存儲輸入。

5

如果你不能矢量化你的calculuations,Python/Numpy會很慢。 Numpy很快,因爲向量化計算髮生在比Python更低的層次上。核心numpy函數全部用C或Fortran編寫。因此sum(a)不是一個有很多訪問的python循環,它是一個低級的C調用。

Numpy's Performance Python demo page有不同的選項很好的例子。通過使用較低級別的編譯語言Cython,或者在可行的情況下使用向量化函數,可以輕鬆獲得100倍的增長。 This blog post顯示使用Cython爲一個numpy用例增加43倍。

+0

你的意思是numpy.sum()? – lizzie 2013-01-25 18:41:26

0

如果array.array的

  • 的訪問速度是你的應用程序可以接受
  • 要使用標準模塊(無NumPy的依賴)
  • 你是
  • 緊湊的存儲是最重要的具有/ dev/zero的平臺

以下內容可能會對您感興趣。它初始化array.array比array.array快約27倍( 'L',[0] *尺寸):

myarray = array.array('L') 
f = open('/dev/zero', 'rb') 
myarray.fromfile(f, size) 
f.close() 

How to initialise an integer array.array object with zeros in Python我正在尋找一個更好的方法。