2009-02-17 127 views
11

我需要從Python腳本中的文件(到Python列表)中加載(反序列化)預先計算的整數列表。該列表很大(高達數百萬個項目),並且只要加載速度最快,我就可以選擇存儲它的格式。Python列表序列化 - 最快的方法

哪個是最快的方法,爲什麼?

  1. 上只包含賦值給變量
  2. 使用列表中cPickleload
  3. 其他一些方法(也許numpy?)

另外一個.py文件使用import,如何人們可以可靠地基準這些東西嗎

附錄:測量這個可靠是困難的,因爲import被緩存,所以它不能在測試中多次執行。在第一次之後,使用pickle的加載也會變得更快,可能是因爲操作系統的頁面預緩存。裝載100萬個數字cPickle第一次運行需要1.1秒,後續執行腳本需要0.2秒。

直覺上我覺得cPickle應該更快,但我會欣賞數字(我認爲這是一個相當大的挑戰)。

是的,這對我來說很重要,它的執行速度很快。

謝謝

+0

這真的是你的代碼的緩慢部分?你多久會加載一次文件? – 2009-02-17 13:23:55

+0

你有沒有試過這些?你現在有什麼指標? – 2009-02-17 13:30:10

+0

對於它的價值,您可以通過使用「execfile()」來避免導入問題... – gahooa 2009-02-19 05:59:27

回答

7

我猜cPickle將是最快的,如果你真的需要列表中的東西。

如果你可以使用一個array,這是一個內置序列類型,我計時這在四分之一秒100萬點的整數:

from array import array 
from datetime import datetime 

def WriteInts(theArray,filename): 
    f = file(filename,"wb") 
    theArray.tofile(f) 
    f.close() 

def ReadInts(filename): 
    d = datetime.utcnow() 
    theArray = array('i') 
    f = file(filename,"rb") 
    try: 
     theArray.fromfile(f,1000000000) 
    except EOFError: 
     pass 
    print "Read %d ints in %s" % (len(theArray),datetime.utcnow() - d) 
    return theArray 

if __name__ == "__main__": 
    a = array('i') 
    a.extend(range(0,1000000)) 
    filename = "a_million_ints.dat" 
    WriteInts(a,filename) 
    r = ReadInts(filename) 
    print "The 5th element is %d" % (r[4]) 
2

「如何可靠地基準這樣的事情?

我不明白這個問題。

你寫了一堆小函數來創建並以各種形式保存你的列表。

你寫了一堆小函數來以各種形式加載你的列表。

您編寫了一個小計時器函數來獲取啓動時間,執行加載過程幾十次(以獲得足夠長的穩定平均值,以使OS調度噪聲不會支配您的測量結果)。

你在一個小報告中總結你的數據。

這有什麼不可靠的?

以下是一些無關的問題,說明如何衡量和比較性能。

Convert list of ints to one number?

String concatenation vs. string substitution in Python

+0

我同意。我就是做這個的。 – 2009-02-17 13:48:00

3

爲標杆,請參閱Python標準庫timeit模塊。要查看最快的方法,請實施所有您可以想到的方法,並用時間對其進行測量。

隨機想法:根據你在做什麼,你可能會發現它最快速地存儲「整數集」在使用的風格。newsrc文件:

1, 3-1024, 11000-1200000 

如果您需要檢查的東西是否是該集合,然後加載並用這樣的表示匹配應該是最快的方式之一。這假設你的整數集合相當密集,連續的相鄰值序列很長。

2

爲了幫助您定時,Python庫提供timeit模塊:

該模塊提供了一個簡單的方法來Python代碼時小位。它既有命令行也有可調用的接口。它避免了測量執行時間的一些常見陷阱。

一個例子(從手動),其比較了使用hasattr()try/except的成本測試丟失的和現在的對象屬性:

% timeit.py 'try:' ' str.__nonzero__' 'except AttributeError:' ' pass' 
100000 loops, best of 3: 15.7 usec per loop 
% timeit.py 'if hasattr(str, "__nonzero__"): pass' 
100000 loops, best of 3: 4.26 usec per loop 
% timeit.py 'try:' ' int.__nonzero__' 'except AttributeError:' ' pass' 
1000000 loops, best of 3: 1.43 usec per loop 
% timeit.py 'if hasattr(int, "__nonzero__"): pass' 
100000 loops, best of 3: 2.23 usec per loop 
1

cPickle的將是最快的,因爲它被保存在二進制文件中,沒有真正的Python代碼必須被解析。

其他優點是它更安全(因爲它不執行命令),並且正確設置$PYTHONPATH沒有問題。

2

您是否需要始終加載整個文件?如果沒有,upack_from()可能是最好的解決方案。假設,你有1000000個整數,但你想加載50000到50099,你會這樣做:

import struct 
intSize = struct.calcsize('i') #this value would be constant for a given arch 
intFile = open('/your/file.of.integers') 
intTuple5K100 = struct.unpack_from('i'*100,intFile,50000*intSize)