2010-08-03 67 views
4

我有一個Python程序處理相當大的NumPy數組(數百兆字節),它們存儲在磁盤上的pickle文件(每個文件一個〜100MB數組)中。當我想對數據運行一個查詢時,我通過pickle加載整個數組,然後執行查詢(以便從Python程序的角度看整個數組在內存中,即使操作系統將其交換出去) 。我這樣做主要是因爲我相信能夠在NumPy數組上使用向量化操作會比使用循環遍歷每個項目快得多。通過NumPy數組迭代的懶惰評估

我正在一個Web服務器上運行該服務器,該服務器的內存限制很快就會遇到。我在數據上運行了許多不同類型的查詢,因此編寫的「分塊」代碼會從單獨的pickle文件加載部分數據,對其進行處理,然後進入下一個塊可能會增加很多複雜性。對於處理這些大型數組的任何函數來說,這個「分塊」是透明的。

看起來理想的解決方案就像是一個發生器,它定期從磁盤加載一塊數據,然後逐個傳遞數組值。這將顯着減少程序所需的內存量,而不需要單獨查詢功能的額外工作。是否有可能做這樣的事情?

+0

也許一個有用的參考:剛剛發現這被稱爲「核心外」任務。 – erich 2010-08-04 18:53:23

回答

9

PyTables是一個包,用於管理分層數據集。它旨在爲您解決這個問題。

2

這似乎是理想的解決辦法 是這樣的一個發生器,它週期性地 加載從磁盤 數據的塊,然後通過一個傳遞的 數組值出一個。這個 將大大減少 程序所需的內存量 ,而不需要在個別查詢 函數的部分上做任何額外的工作。是否有可能做 這樣的事情?

是的,但不是通過將磁盤陣列保存在一個pickle中 - pickle協議並不是爲「incremental deserialization」設計的。

可以寫入多個泡菜到同一個打開的文件,一前一後(使用dumpdumps),然後將「懶惰評估迭代」只需要每次都使用pickle.load

實施例的代碼(Python的3.1 - 在凡因你要cPickle代替pickle和協議的-1,當然;-)等:

>>> import pickle 
>>> lol = [range(i) for i in range(5)] 
>>> fp = open('/tmp/bah.dat', 'wb') 
>>> for subl in lol: pickle.dump(subl, fp) 
... 
>>> fp.close() 
>>> fp = open('/tmp/bah.dat', 'rb') 
>>> def lazy(fp): 
... while True: 
...  try: yield pickle.load(fp) 
...  except EOFError: break 
... 
>>> list(lazy(fp)) 
[range(0, 0), range(0, 1), range(0, 2), range(0, 3), range(0, 4)] 
>>> fp.close() 
4

NumPy的內存映射的數據結構MEMMAP)可能會在這裏一個不錯的選擇。

您可以從磁盤上的二進制文件訪問您的NumPy數組,而無需將整個文件一次加載到內存中。

(注意,我相信,但我不肯定的,那Numpys MEMMAP對象一樣蟒蛇 - 尤其NumPys是陣列狀,Python的是文件等。)

該方法的簽名是:

A = NP.memmap(filename, dtype, mode, shape, order='C') 

所有參數是直截了當的(即,它們具有如NumPy的其它地方使用的相同的含義),除了「訂單」,它指的是ndarray存儲器佈局的順序。我相信缺省值是'C',而Fortran的(唯一)其他選項是'F' - 與其他地方一樣,這兩個選項分別代表行主和列主指令。

這兩種方法是:

沖洗(其寫入到磁盤您對陣列的任何改變);和

靠近(其將數據寫入到MEMMAP陣列,或更精確地存儲在磁盤上的陣列狀的內存映射到數據)

例如使用:

import numpy as NP 
from tempfile import mkdtemp 
import os.path as PH 

my_data = NP.random.randint(10, 100, 10000).reshape(1000, 10) 
my_data = NP.array(my_data, dtype="float") 

fname = PH.join(mkdtemp(), 'tempfile.dat') 

mm_obj = NP.memmap(fname, dtype="float32", mode="w+", shape=1000, 10) 

# now write the data to the memmap array: 
mm_obj[:] = data[:] 

# reload the memmap: 
mm_obj = NP.memmap(fname, dtype="float32", mode="r", shape=(1000, 10)) 

# verify that it's there!: 
print(mm_obj[:20,:]) 
+0

如果你不想經歷安裝PyTables的麻煩,這真的很方便。 – erich 2010-08-05 19:30:46