代码包含在函数中时是否获得了内存效率?

时间:2009-05-28 03:52:03

标签: python memory-management function

我一直在研究一些代码。我通常的方法是首先解决问题的所有部分,创建循环和我需要的其他代码片段,因为我解决问题,然后如果我希望重用代码,我会回过头来整理部分我认为应该将代码编组在一起以创建函数。

我刚才注意到,创建函数并调用它们似乎比编写代码行和删除容器更有效率。

例如:

def someFunction(aList):
    do things to aList
    that create a dictionary
    return aDict

似乎最终释放的内存比

更多
>>do things to alist
>>that create a dictionary
>>del(aList)

这是预期的行为吗?

EDIT添加了示例代码

当此功能完成运行时,PF Usage显示增加约100 mb,filingsList有大约800万行。

def getAllCIKS(filingList):
    cikDICT=defaultdict(int)
    for filing in filingList:
        if filing.startswith('.'):
            del(filing)
            continue
        cik=filing.split('^')[0].strip()
        cikDICT[cik]+=1
        del(filing)
    ciklist=cikDICT.keys()
    ciklist.sort()
return ciklist

allCIKS=getAllCIKS(open(r'c:\filinglist.txt').readlines())

如果我这样做,我会显示增加近400 mb

cikDICT=defaultdict(int)
for filing in open(r'c:\filinglist.txt').readlines():
    if filing.startswith('.'):
        del(filing)
        continue
    cik=filing.split('^')[0].strip()
    cikDICT[cik]+=1
    del(filing)

ciklist=cikDICT.keys()
ciklist.sort()
del(cikDICT)

EDIT 今天我一直在玩这个。我的观察和问题应该有所改进,因为我的重点是PF用法。不幸的是,我只能在其他任务之间捅这个。但是我开始怀疑引用与副本。如果我从列表中创建字典,字典容器是否包含来自列表的值的副本,或者它们是否保留对列表中值的引用?我敢打赌,复制的值不是引用的。

我注意到的另一件事是GC列表中的项目是来自已删除容器的项目。那有意义吗?所以我有一个列表,并假设列表中的每个项目是[(aTuple),anInteger,[另一个列表]]。当我开始学习如何操作gc对象并检查它们时,我在gc中找到了那些对象,即使列表已被强制删除,即使我通过了0,1& 2值我不记得尝试仍然删除它们的方法。

我很欣赏人们分享的见解。不幸的是,我总是想知道如何在幕后工作。

5 个答案:

答案 0 :(得分:3)

也许你在函数中使用了一些局部变量,它们在函数末尾通过引用计数隐式释放,而它们不会在代码段结束时释放?

答案 1 :(得分:1)

您可以使用提供的Python garbage collector interface更仔细地检查在第二种情况下遗留的内容(如果有的话)。具体来说,您可能需要查看gc.get_objects()以查看未收集的内容,或gc.garbage查看是否有任何参考周期。

答案 2 :(得分:0)

从函数返回时会释放一些额外的内存,但这与为首先调用函数分配的额外内存完全相同。在任何情况下 - 如果你看到大量的差异,这可能是运行时状态的神器,并不是你应该真正担心的事情。如果内存不足,解决问题的方法是使用b-tree(或仅使用数据库)等方法在磁盘上保留更多数据,或者使用内存较少的算法。另外,请留意制作大量数据结构的不必要副本。

创建函数时的实际内存节省是在短期内存中。通过将某些内容移动到函数中,可以通过封装部分细节来减少需要记住的细节数量。

答案 3 :(得分:0)

也许你应该重新设计你的代码以摆脱不必要的变量(可能不会立即释放)......下面的代码片段怎么样?

myfile = file(r"c:\fillinglist.txt")
ciklist = sorted(set(x.split("^")[0].strip() for x in myfile if not x.startswith(".")))
编辑:我不知道为什么这个答案被否决...也许是因为它很短?或者也许是因为投票的家伙无法理解这个单行如何与问题中的代码相同而不创建不必要的时间容器?

唉...

答案 4 :(得分:0)

我问了另一个关于复制列表和答案的问题,特别是指导我看深度复制的答案让我想到了一些字典行为。我遇到的问题与原始列表永远不会被垃圾收集的事实有关,因为字典维护对列表的引用。我需要在Python Docs中使用有关weakref的信息。

词典引用的对象似乎还活着。我认为(但不确定)将字典推出函数的过程会强制复制过程并杀死对象。这还不完整我需要做更多的研究。