gpt4 book ai didi

python - Python 中的巨大内存成本

转载 作者:行者123 更新时间:2023-11-28 22:36:15 25 4
gpt4 key购买 nike

我正在编写一段使用 Python 中的对象的代码。我有 1.1GB 的文件需要解析并转换为对象。

但是,1.1GB 的文件,它消耗了超过 7GB 的内存(我停止了它,因为它可以走得更远......),这是挺大。我使用内存分析器检查并查看发生了什么,并且......有一个我得到的结果示例:

Line #    Mem usage    Increment   Line Contents
================================================
78 30.352 MiB 0.000 MiB @profile
79 def getInfos(listExch):
80
81 30.352 MiB 0.000 MiB SizeTot = 0
82 30.352 MiB 0.000 MiB upListExch = set()
83
84 5325.996 MiB 5295.645 MiB for exch in listExch:
85
86
87 5325.996 MiB 0.000 MiB symbExch = exch.symb
88 5325.996 MiB 0.000 MiB nameExch = exch.name
89 5325.996 MiB 0.000 MiB stList = exch.getStList()
90 5325.996 MiB 0.000 MiB upExch = Exch(symbExch,nameExch)
91
92 7572.309 MiB 2246.312 MiB for st in stList:
93
94 7572.309 MiB 0.000 MiB unexpected = False
95 7572.309 MiB 0.000 MiB symbSt = st.symb
96
97 7572.309 MiB 0.000 MiB filepath = '{0}/{1}.csv'.format(download_path,symbSt)
98
99 7572.309 MiB 0.000 MiB upSt = parseQ(st,filepath)
100 7572.309 MiB 0.000 MiB upExch.addSt(upSt)
101 5325.996 MiB -2246.312 MiB upListExch.add(upExch)
102
103 return upListExch

下面还有我写的对象模型:

Exch 是一个包含listSt 的对象,每个St 包含对象的listQ

class Exch:
def __init__(self,symb,name):
self.symb = symb
self.name = name
self.listSt = set()

def addSt(self,st):
self.listSt.add(st)

def setStList(self,listSt):
self.listSt = listSt

def getStList(self):
return self.listSt

class St:
def __init__(self,symb,name):
self.symb = symb
self.name = name
self.listQ = set()

def getQList(self):
return self.listQ

def addQ(self,q):
self.listQ.add(q)

class Q:

def __init__(self,date,dataH,dataM,dataL):

self.date = date
self.dataH = dataH
self.dataM = dataM
self.dataL = dataL

我是不是做错了什么?或者 Python 不适应这种数据量?

编辑:

输入的listExch包含一个Exch对象的列表,listSt中的每个st包含一个空的listQ

除了将添加每个 st 对象中的每个 listQ 之外,输出将与输入相同。

解析器是这样的:

def parseQ(st,filepath):

loc_date,loc_dataH,loc_dataM,loc_dataL = 0,0,0,0

with open (filepath, 'rt') as csvfile:
reader = csv.reader (csvfile,delimiter=',')
row1 = next(reader)
unexpected = False

for idx,el in enumerate(row1):
if (el == 'Date'):
loc_date = idx
elif (el == 'Number High'):
loc_dataH = idx
elif (el == 'Number Medium'):
loc_dataM = idx
elif (el == 'Number Low'):
loc_dataL = idx
else:
log.error('Unexpected format on file {}. Skip the file'.format(filepath))
unexpected = True
break
if (unexpected):
log.error('The file "{}" is not properly set'.format(filepath))
return False
else:
next(reader)
for row in reader:
try:
st.addQ(Q(row[loc_date],row[loc_dataH],row[loc_dataM],row[loc_dataL]))
return st

最佳答案

我一点也不惊讶。

读取 CSV 文件会生成一个行列表,每一行都指向一个元素列表。

现在,每个 都是一个 PyObject,这意味着它有一个 typeref,我认为通常使用 size_t,并且包含它的列表必须包含它的 id(巧合的是,它只是指向 PyObject 的指针),所以这是两个 size_t,即指针类型的大小,只是因为有一个元素。这甚至没有考虑元素的“有效负载”也需要一点内存的事实!

在 64 位机器上,这将是 128 位的纯结构开销每个元素。我不知道您的元素是什么样子,但这很可能比实际内容更多。

一般来说,不要这样做。如果你的数据是表格的,用 numpy 加载它,它不会有列表的 python 列表,而只是分配一大块内存来转储原始值并在访问它们时计算单个元素地址,而不是走 Python 路线从一个指针跳到另一个指针。这样一来,您也会获得很大的速度。

我还要提一下,CSV 是一种特别不适合存储大量数据的格式。没有语言的正式定义(这就是为什么 python 的 CSV 阅读器有“方言”的概念),它在存储 float 方面效率极低(并且可能不精确),如果不阅读 all 就没有机会访问第 N 行 N-1 前面的行,它取决于字符串解析,不能用于就地修改值,除非这不会改变字符串的长度......总而言之:你做得很好如果您读入这些文件一次,并将它们转换成某种实际存储方式的表格格式。

“但 CSV 是纯文本,我可以用我的文本编辑器阅读它”的论点并不重要——没有人能够“快速点击”1GB 的 CSV。因此,请尝试摆脱 CSV 文件。 Numpy,同样有一个本地存储格式,它可能适合你的目的,或者使用 HDF 或任何其他标准格式——或者如果你的 CSV 的所有元素都属于同一类型,你也可以将它们保存为你的原始字节图像数据——这将是最快和最节省空间的存储方法(但你必须“从外部”记住数据的结构),稀疏性放在一边。

编辑:正如 OP 指出的那样, 正是他的计划:读取 CSV,验证其内容,然后将其存储在数据库中!风格不错。

现在,读取可以按行进行,因此您可以读取一行(或几行),将数据存储在数据库中,忘记行,获取下一行,等等。验证可以发生在存储在数据库中的数据上,可能发生在数据库的一个单独的“暂存”部分。

关于python - Python 中的巨大内存成本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37632526/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com