19

我试图处理将大量腌制数据分小块写入磁盘的问题。这是示例代码:

from cPickle import *
from gc import collect

PATH = r'd:\test.dat'
@profile
def func(item):
    for e in item:
        f = open(PATH, 'a', 0)
        f.write(dumps(e))
        f.flush()
        f.close()
        del f
        collect()

if __name__ == '__main__':
    k = [x for x in xrange(9999)]
    func(k)

open() 和 close() 放置在循环内,以排除内存中数据积累的可能原因。

为了说明问题,我附上了使用 Python 3d 方模块memory_profiler获得的内存分析结果:

   Line #    Mem usage  Increment   Line Contents
==============================================
    14                           @profile
    15      9.02 MB    0.00 MB   def func(item):
    16      9.02 MB    0.00 MB       path= r'd:\test.dat'
    17
    18     10.88 MB    1.86 MB       for e in item:
    19     10.88 MB    0.00 MB           f = open(path, 'a', 0)
    20     10.88 MB    0.00 MB           f.write(dumps(e))
    21     10.88 MB    0.00 MB           f.flush()
    22     10.88 MB    0.00 MB           f.close()
    23     10.88 MB    0.00 MB           del f
    24                                   collect()

在循环执行期间,会出现奇怪的内存使用量增长。怎样才能消除?有什么想法吗?

当输入数据量增加时,这些附加数据的量可以增长到比输入大得多的大小(更新:在实际任务中,我得到 300+Mb)

还有更广泛的问题——有哪些方法可以在 Python 中正确处理大量 IO 数据?

upd: 我重写了只留下循环体的代码,以查看具体何时发生增长,结果如下:

Line #    Mem usage  Increment   Line Contents
==============================================
    14                           @profile
    15      9.00 MB    0.00 MB   def func(item):
    16      9.00 MB    0.00 MB       path= r'd:\test.dat'
    17
    18                               #for e in item:
    19      9.02 MB    0.02 MB       f = open(path, 'a', 0)
    20      9.23 MB    0.21 MB       d = dumps(item)
    21      9.23 MB    0.00 MB       f.write(d)
    22      9.23 MB    0.00 MB       f.flush()
    23      9.23 MB    0.00 MB       f.close()
    24      9.23 MB    0.00 MB       del f
    25      9.23 MB    0.00 MB       collect()

似乎 dumps() 吃掉了内存。(虽然我实际上认为它会是 write())

4

1 回答 1

15

泡菜消耗大量内存,请参阅此处的解释:http: //www.shocksolution.com/2010/01/storing-large-numpy-arrays-on-disk-python-pickle-vs-hdf5adsf/

为什么 Pickle 会消耗这么多内存?原因是 HDF 是二进制数据管道,而 Pickle 是对象序列化协议。Pickle 实际上由一个简单的虚拟机 (VM) 组成,它将一个对象转换为一系列操作码并将它们写入磁盘。为了解开某些东西,VM 读取并解释操作码并重建一个对象。这种方法的缺点是 VM 必须在将对象写入磁盘之前在内存中构建对象的完整副本。

Pickle 非常适合小型用例或测试,因为在大多数情况下,内存消耗并不重要。

对于必须转储和加载大量文件和/或大文件的密集工作,您应该考虑使用另一种方式来存储数据(例如:hdf,为您的对象编写自己的序列化/反序列化方法,...)

于 2016-08-16T09:38:39.967 回答