一次读取多个Python pickle数据,缓冲和换行?

san*_*san 9 python newline buffering pickle

给你上下文:

我有一个大文件f,几个Gigs的大小.它包含通过运行生成的不同对象的连续pickle

for obj in objs: cPickle.dump(obj, f)

我想在阅读此文件时利用缓冲.我想要的是一次将几个拾取的对象读入缓冲区.这样做的最佳方式是什么?我想要一个readlines(buffsize)腌制数据的模拟.事实上,如果挑选的数据确实是换行符,则可以使用readlines,但我不确定这是否属实.

我想到的另一个选择是首先dumps()将pickled对象转换为字符串,然后将字符串写入文件,每个文件用换行符分隔.要读回文件,我可以使用readlines()loads().但是我担心一个腌制的物体可能有这个"\n"角色,它会抛弃这个文件读取方案.我的恐惧没有根据吗?

一种选择是将其作为一个巨大的对象列表来剔除,但这将需要比我能承受的更多的内存.可以通过多线程加速设置,但我不想在缓冲工作正常之前去那里.什么是这种情况下的"最佳实践".

编辑:我还可以将原始字节读入缓冲区并调用其上的负载,但我需要知道负载消耗了多少字节的缓冲区,以便我可以抛弃它.

Sin*_*ion 6

我想你不需要做任何事情.

>>> import pickle
>>> import StringIO
>>> s = StringIO.StringIO(pickle.dumps('apples') + pickle.dumps('bananas'))
>>> pickle.load(s)
'apples'
>>> pickle.load(s)
'bananas'
>>> pickle.load(s)

Traceback (most recent call last):
  File "<pyshell#25>", line 1, in <module>
    pickle.load(s)
  File "C:\Python26\lib\pickle.py", line 1370, in load
    return Unpickler(file).load()
  File "C:\Python26\lib\pickle.py", line 858, in load
    dispatch[key](self)
  File "C:\Python26\lib\pickle.py", line 880, in load_eof
    raise EOFError
EOFError
>>> 
Run Code Online (Sandbox Code Playgroud)


Kir*_*ser 5

file.readlines()返回文件全部内容的列表.你想一次读几行.我认为这个天真的代码应该取消您的数据:

import pickle
infile = open('/tmp/pickle', 'rb')
buf = []
while True:
    line = infile.readline()
    if not line:
        break
    buf.append(line)
    if line.endswith('.\n'):
        print 'Decoding', buf
        print pickle.loads(''.join(buf))
        buf = []
Run Code Online (Sandbox Code Playgroud)

如果您对生成泡菜的程序有任何控制权,我会选择以下方法之一:

  1. 使用该shelve模块.
  2. 在将每个pickle写入文件之前打印每个pickle的长度(以字节为单位),以便您确切地知道每次要读取多少字节.
  3. 与上面相同,但将整数列表写入单独的文件,以便您可以将这些值用作包含pickle的文件的索引.
  4. 一次挑选一个K对象列表.以字节为单位写出该pickle的长度.写泡菜.重复.

顺便说一下,我怀疑它file的内置缓冲应该可以让你获得99%的性能提升.

如果您确信I/O阻止了您,您是否考虑过尝试mmap()并让操作系统一次处理打包?

#!/usr/bin/env python

import mmap
import cPickle

fname = '/tmp/pickle'
infile = open(fname, 'rb')
m = mmap.mmap(infile.fileno(), 0, access=mmap.ACCESS_READ)
start = 0
while True:
    end = m.find('.\n', start + 1) + 2
    if end == 1:
        break
    print cPickle.loads(m[start:end])
    start = end
Run Code Online (Sandbox Code Playgroud)