2009-02-17 131 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)