繁体   English   中英

Python的巨大内存成本

[英]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对象,并且每个stlistSt包含一个空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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM