【问题标题】:Python (+django) absent garbage collection in simple scriptPython(+django)在简单脚本中没有垃圾收集
【发布时间】:2015-08-27 22:36:10
【问题描述】:

所以我在 python 中有这个脚本。 它使用 django 的模型从数据库中获取一些(准确地说:很多)数据。

我想要实现的目标的快速“总结”(它可能不是那么重要,所以你也可以通过查看代码来获得它):
有A类型的对象。
对于每个 A 对象,都有 B 类型的相关对象(1 到多个)。
对于每个 B 对象,都有 C 类型的相关对象(1 到多个)。
对于每个 C 对象,都有一个对我来说特别有趣的相关对象——我们称之为 D(1 对 1 关系)。

对于数据库中的每个 A 对象(不是很多),我需要获取与其相关的所有 B 对象以及与其相关的所有 D 对象,以创建 A 对象的摘要。每个摘要都是一个单独的工作表(我使用的是 openpyxl)。

我写的代码是有效的(意思是:它做我想做的事),但是垃圾收集有问题,所以进程被杀死了。我试过不使用预取,因为时间不是那么重要,但它并没有真正的帮助。

抽象代码:

a_objects = A.objects.all()
wb = Workbook()

for a_object in a_objects:
    ws = wb.create_sheet()
    ws.title = a.name
    summary_dictionary = {}
    << 1 >>
    b_objects = B.objects.filter(a_object=a_object)

    for b_object in b_objects:
        c_objects = C.objects.filter(b_object=b_object)
        for c_object in c_objects:
            # Here i put a value in dictionary, or alter it, 
            # depending on whether c_object.d_object has unique fields for current a_object
            # Key is a tuple of 3 floats (taken from d_object)
            # Value is array of 3 small integers (between 0 and 100) 

    summary_dictionary = sorted(summary_dictionary.items(), key=operator.itemgetter(0))

    for summary_item in summary_dictionary:
        ws.append([summary_item[0][0], summary_item[0][1], summary_item[0][2], summary_item[1][0], summary_item[1][1], summary_item[1][2], sum(summary_item[1])])

wb.save("someFile.xlsx")

虽然理论上整个 xlsx 文件可能很大 - 可能超过 1GB,但如果所有 d_objects 值都是唯一的,我估计即使在脚本结束时它也低于 100 MB。在执行脚本时,系统中大约有 650 MB 可用内存。

大约有 80 个 A 对象,脚本在其中 6 或 7 个之后被杀死。我使用“top”来监控内存使用情况,但没有注意到任何内存被释放,这很奇怪,因为,比方说:
第 3 个 a_object 有 1000 个 b_object 与之相关,每个 b_object 有 30 个 c_object 与之相关,并且 第 4 个 a_object 只有 100 个 b_object 与之相关,每个 b_object 只有 2 个 c_object 与之相关。

在第 4 次迭代的 > 之后的某个时间应该释放大量内存,对吗?
我的观点是,我认为这个程序的行为应该是,只要以下内容可以放入内存,它就会运行:
- 整个摘要
- 数据库中任何 a_object 的所有 b_objects 及其 c_objects 及其 d_objects 的单一集合。

那我错过了什么?

【问题讨论】:

    标签: python django model garbage-collection


    【解决方案1】:

    尝试切换:

    a_objects = A.objects.all()
    

    到:

    a_objects = A.objects.all().iterator()
    

    【讨论】:

    • 我明天会试一试,还有其他对象(b 和 c),因为 a 在这里意义最小(大约只有 80 个)
    • 另外,我真的不明白它会有什么帮助。我知道迭代器会阻止缓存,但是当在 > 之后删除对查询集的引用时,应该对缓存的对象进行垃圾收集,不是吗?
    猜你喜欢
    • 2011-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-29
    • 1970-01-01
    • 2013-10-18
    相关资源
    最近更新 更多