I'm facing a memory error in my code. My parser could be summarized like that:
# coding=utf-8
#! /usr/bin/env python
import sys
import json
from collections import defaultdict
class MyParserIter(object):
def _parse_line(self, line):
for couple in line.split(","):
key, value = couple.split(':')[0], couple.split(':')[1]
self.__hash[key].append(value)
def __init__(self, line):
# not the real parsing just a example to parse each
# line to a dict-like obj
self.__hash = defaultdict(list)
self._parse_line(line)
def __iter__(self):
return iter(self.__hash.values())
def to_dict(self):
return self.__hash
def __getitem__(self, item):
return self.__hash[item]
def free(self, item):
self.__hash[item] = None
def free_all(self):
for k in self.__hash:
self.free(k)
def to_json(self):
return json.dumps(self.to_dict())
def parse_file(file_path):
list_result = []
with open(file_path) as fin:
for line in fin:
parsed_line_obj = MyParserIter(line)
list_result.append(parsed_line_obj)
return list_result
def write_to_file(list_obj):
with open("out.out", "w") as fout:
for obj in list_obj:
json_out = obj.to_json()
fout.write(json_out + "\n")
obj.free_all()
obj = None
if __name__ == '__main__':
result_list = parse_file('test.in')
print(sys.getsizeof(result_list))
write_to_file(result_list)
print(sys.getsizeof(result_list))
# the same result for memory usage result_list
print(sys.getsizeof([None] * len(result_list)))
# the result is not the same :(
The aim is to parse (large) file, each line transformed to a json object that will be written back to a file.
My goal is to reduce the footprint because in some case this code raises a Memory error. After each fout.write
i would like delete (free memory) obj
reference.
I tried to set obj
to None of call the method obj.free_all()
but none of them free the memory. I also used simplejson rather than json, that have reduced the footprint but still to too large in some cases.
test.in is looking like:
test1:OK,test3:OK,...
test1:OK,test3:OK,...
test1:OK,test3:OK,test4:test_again...
....
Don't store many instance of class in array, instead do it inline. Example.
% cat test.in
test1:OK,test3:OK
test1:OK,test3:OK
test1:OK,test3:OK,test4:test_again
% cat test.py
import json
with open("test.in", "rb") as src:
with open("out.out", "wb") as dst:
for line in src:
pairs, obj = [x.split(":",1) for x in line.rstrip().split(",")], {}
for k,v in pairs:
if k not in obj: obj[k] = []
obj[k].append(v)
dst.write(json.dumps(obj)+"\n")
% cat out.out
{"test1": ["OK"], "test3": ["OK"]}
{"test1": ["OK"], "test3": ["OK"]}
{"test1": ["OK"], "test3": ["OK"], "test4": ["test_again"]}
If it is slow, don't write to file line by line, but store dumped json string in array and do dst.write("\n".join(array))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With