我得到了关于de / serialization的earlier question的一个很好的答案,这使我创建了一个方法,可以从文件中反序列化defaultdict(list)
(如果存在),或者创建字典本身文件不存在。
实施简单代码后
try:
#deserialize - this takes about 6 seconds
with open('dict.flat') as stream:
for line in stream:
vals = line.split()
lexicon[vals[0]] = vals[1:]
except:
#create new - this takes about 40 seconds
for word in lexicon_file:
word = word.lower()
for letter n-gram in word:
lexicon[n-gram].append(word)
#serialize - about 6 seconds
with open('dict.flat', 'w') as stream:
stream.write('\n'.join([' '.join([k] + v) for k, v in lexicon.iteritems()]))
我对从文件反序列化时脚本占用的内存量感到有些震惊。
(lexicon_file包含大约620 000个单词,处理过的defaultdict(list)
包含25 000个键,而每个键包含1到133 000个字符串的列表(平均500个,中位数20)。
每个键都是一个字母bi / trigram,它的值是包含关键字母n-gram的单词。)
当脚本重新创建词典时,整个过程不会使用超过160 MB的RAM - 序列化文件本身略高于129 MB。 当脚本反序列化词典时,python.exe占用的RAM量最多会跳到500 MB。
当我尝试使用
模拟在反序列化过程中创建新词典的方法时#deserialize one by one - about 15 seconds
with open('dict.flat') as stream:
for line in stream:
vals = line.split()
for item in vals[1:]:
lexicon[vals[0]].append(item)
结果完全相同 - 除了此代码段运行速度明显变慢。
是什么导致内存消耗的这种巨大差异?我的第一个问题是,由于结果列表中的很多元素完全相同,因此python以某种方式使用引用更有效地创建字典 - 在反序列化和将整个列表映射到键时没有时间。但如果是这种情况,为什么这个问题没有通过逐个附加项来解决,就像创建一个新的词典一样?
编辑:this question已经讨论过这个话题了(我怎么错过了?!)。可以使用intern()
函数强制Python从引用创建字典:
#deserialize with intern - 45 seconds
with open('dict.flat') as stream:
for line in stream:
vals = line.split()
for item in vals[1:]:
lexicon[intern(vals[0])].append(intern(item))
这减少了字典对预期值(160 MB)所占用的RAM量,但偏移量是计算时间恢复到与重新创建字典时相同的值,这完全否定了序列化的原因。