Почему мариновать едят память?
Я пытаюсь записать огромное количество засоленных данных на диск небольшими порциями. Вот пример кода:
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 party.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()
При выполнении цикла происходит странное увеличение использования памяти. Как это можно устранить? Какие-нибудь мысли?
Когда количество входных данных увеличивается, объем этих дополнительных данных может вырасти до размера, намного превышающего входной (upd: в реальной задаче я получаю 300+ Мб)
И более широкий вопрос - какие существуют способы для правильной работы с большими объемами данных ввода-вывода в Python?
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 () ест память. (Пока я на самом деле думал что напишу ())