Python csv.DictReader的内存使用问题
我在Python3中使用它来处理一个非常大的CSV文件。我发现了一个奇怪的内存使用问题 代码是这样的Python csv.DictReader的内存使用问题,python,memory-management,Python,Memory Management,我在Python3中使用它来处理一个非常大的CSV文件。我发现了一个奇怪的内存使用问题 代码是这样的 import os import csv import psutil # require pip install # the real CSV file is replaced with a call to this function def generate_rows(): for k in range(400000): yield ','.join(str(i *
import os
import csv
import psutil # require pip install
# the real CSV file is replaced with a call to this function
def generate_rows():
for k in range(400000):
yield ','.join(str(i * 10 + k) for i in range(35))
def memory_test():
proc = psutil.Process(os.getpid())
print('BEGIN', proc.memory_info().rss)
fieldnames = ['field_' + str(i) for i in range(35)]
reader = csv.DictReader(generate_rows(), fieldnames)
result = []
for row in reader:
result.append(row)
print(' END', proc.memory_info().rss)
return result
if __name__ == '__main__':
memory_test()
在上面的代码中,程序将打印内存使用情况(需要安装psutil
),结果如下
BEGIN 12623872
END 2006462464
BEGIN 12726272
END 1289912320
您可以看到,在进程结束时,它将占用近2GB的内存
但是如果我复制每一行,内存使用就会降低
def memory_test():
proc = psutil.Process(os.getpid())
print('BEGIN', proc.memory_info().rss)
fieldnames = ['field_' + str(i) for i in range(35)]
reader = csv.DictReader(generate_rows(), fieldnames)
result = []
for row in reader:
# MAKE A COPY
row_copy = {key: value for key, value in row.items()}
result.append(row_copy)
print(' END', proc.memory_info().rss)
return result
结果是
BEGIN 12623872
END 2006462464
BEGIN 12726272
END 1289912320
它只需要大约1.29G内存,要少得多
(我在64位Ubuntu上测试了代码,得到了这些结果。)
为什么会发生这种情况?从读写器
复制行是否合适?如果打印(行)
,您会发现行
是一个有序的读写器
。在第二个示例中,您将此OrderedDict
替换为正常的dict
。他们是不同的
在第二个示例中,使用orderedict
可以获得相同的结果:
for row in reader:
from collections import OrderedDict
# MAKE A COPY
row_copy = OrderedDict({key: value for key, value in row.items()})
result.append(row_copy)
顺便说一句,如果你想让这段代码更有效率,你可以编写result=list(csv.DictReader(generate_rows(),fieldnames))
——这样可以避免多次追加到列表,这会导致CPython不断重新分配内存以增加列表的大小。@elias确实如此。我只是保留了代码的外观,因为在实际代码中对行
对象有一些更改。如果可能的话,将这些更改移动到函数中并将其转换为列表理解result=[change_row(row)for row in csv.DictReader(…)]