Python列表序列化 - 最快的方法

时间:2009-02-17 13:16:25

标签: python serialization caching

我需要从Python脚本中的文件(到Python列表)中加载(反序列化)预先计算的整数列表。列表很大(高达数百万项),只要加载速度最快,我就可以选择存储它的格式。

哪种方法最快,为什么?

  1. 在.py文件上使用import,该文件只包含分配给变量的列表
  2. 使用cPickle的{​​{1}}
  3. 其他一些方法(也许是load?)
  4. 此外,如何可靠地对这些事情进行基准测试?

    附录:很难对此进行测量很困难,因为numpy已缓存,因此无法在测试中多次执行。第一次使用pickle加载也会因为操作系统的页面预先缓存而变得更快。使用import加载100万个数字第一次运行需要1.1秒,后续执行脚本需要0.2秒。

    直觉我觉得cPickle应该更快,但我会欣赏数字(我认为这是一个非常难以衡量的挑战)。

    是的,对我来说这很重要。

    由于

6 个答案:

答案 0 :(得分: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])

答案 1 :(得分:3)

有关基准测试,请参阅Python标准库中的timeit模块。要了解最快的方法,请实施您能想到的所有方法并使用timeit进行测量。

随机思考:根据您正在做的事情,您可能会发现以 .newsrc 文件中使用的样式存储“整数组”的速度最快:

1, 3-1024, 11000-1200000

如果你需要检查那个集合中是否有东西,那么加载和匹配这样的表示应该是最快的方法。这假设您的整数集合相当密集,具有相邻值的长连续序列。

答案 2 :(得分:2)

“如何可靠地对这些事情进行基准测试?”

我不明白这个问题。

您编写了许多小函数来以各种形式创建和保存列表。

您编写了一些小函数来以各种形式加载列表。

你写了一个小计时器函数来获取开始时间,执行加载程序几十次(得到一个足够长的稳定平均值,以至于OS调度噪声不会影响你的测量)。

您可以在一份小报告中总结您的数据。

这有什么不可靠的?

以下是一些不相关的问题,展示了如何衡量和比较绩效。

Convert list of ints to one number?

String concatenation vs. string substitution in Python

答案 3 :(得分: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

答案 4 :(得分: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)

答案 5 :(得分:1)

cPickle将是最快的,因为它以二进制保存,并且不需要解析真正的python代码。

其他优点是它更安全(因为它不执行命令)并且你没有正确设置$PYTHONPATH的问题。