[英]Huge cost of Memory in Python
我正在編寫一段在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
對象,並且每個st
到listSt
包含一個空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閱讀器具有“方言”概念的原因),它在存儲浮點數方面效率極低(並且可能不精確),沒有機會在不讀取所有 N-1的情況下訪問N行前幾行取決於字符串分析,除非用於更改字符串的長度,否則不能用於就地修改值……總而言之:如果一次讀取這些文件,您的狀態會很好,然后將它們轉換為一些實際的存儲表格格式。
“但是CSV是純文本的,我可以使用文本編輯器閱讀”參數並沒有真正意義-沒有人能夠“快速點擊” 1GB CSV。 因此,請嘗試擺脫CSV文件。 Numpy同樣具有本機存儲格式,可以滿足您的需要,或者使用HDF或任何其他標准格式–或者,如果CSV的所有元素都屬於同一類型,則也可以將它們另存為原始字節圖像數據–這將是最快,最節省空間的存儲方法(但是您必須“從外部”記住數據的結構),除了稀疏性。
編輯 :正如OP所指出的, 這正是他的計划:讀取CSV,驗證其內容,然后將其存儲在數據庫中! 好作風。
現在,讀取可以逐行進行,因此您可以讀取一行(或幾行),將數據存儲在數據庫中,忘記行,獲取下一行,依此類推。 驗證可以在數據庫中存儲的數據上進行,可能在數據庫的單獨“登台”部分中進行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.