gpt4 book ai didi

python - 如何强制从内存中释放 Django 模型

转载 作者:太空狗 更新时间:2023-10-29 17:05:26 24 4
gpt4 key购买 nike

我想使用管理命令对马萨诸塞州的建筑物进行一次性分析。我已将有问题的代码缩减为 8 行代码片段,以演示我遇到的问题。这些评论只是解释了我为什么要这样做。我正在逐字运行下面的代码,在一个否则为空白的管理命令中

zips = ZipCode.objects.filter(state='MA').order_by('id')
for zip in zips.iterator():
buildings = Building.objects.filter(boundary__within=zip.boundary)
important_buildings = []
for building in buildings.iterator():
# Some conditionals would go here
important_buildings.append(building)
# Several types of analysis would be done on important_buildings, here
important_buildings = None

当我运行这段确切的代码时,我发现内存使用量随着每次迭代外循环而稳步增加(我使用 print('mem', process.memory_info().rss) 检查内存使用量).

似乎 important_buildings 列表正在占用内存,即使在超出范围之后也是如此。如果我将 important_buildings.append(building) 替换为 _ = building.pk,它不再消耗太多内存,但我确实需要该列表进行一些分析。

所以,我的问题是:如何强制 Python 在超出范围时释放 Django 模型列表?

编辑:我觉得堆栈溢出有点像陷阱 22——如果我写得太多细节,没有人愿意花时间阅读它(这会成为一个不太适用的问​​题),但如果我写得太详细,我可能会忽略部分问题。不管怎样,我真的很感谢你的回答,并计划在这个周末尝试一些建议,当我终于有机会回到这个问题上时!!

最佳答案

非常快速的回答:正在释放内存,rss 不是一个非常准确的工具来告诉内存在哪里被消耗rss 给出了进程使用内存的度量,而不是进程使用的内存(继续阅读以查看演示),您可以使用包 memory-profiler为了逐行检查函数的内存使用情况。

那么,如何强制从内存中释放 Django 模型?您不能仅使用 process.memory_info().rss 判断是否存在此类问题。

不过,我可以为您提出一个优化代码的解决方案。并编写一个演示,说明为什么 process.memory_info().rss 不是一个非常准确的工具来测量在某些代码块中被使用的内存。

建议的解决方案:正如稍后在同一篇文章中所展示的那样,将 del 应用于列表并不是解决方案,使用 chunk_size 进行优化> for iterator 会有所帮助(请注意 iteratorchunk_size 选项已添加到 Django 2.0 中),这是肯定的,但这里真正的敌人是那个讨厌的 list 。

也就是说,您可以使用执行分析所需的字段列表(我假设您的分析不能同时处理一栋建筑物)以减少存储在该列表中的数据量.

尝试只获取您需要的属性,并使用 Django 的 ORM 选择目标建筑物。

for zip in zips.iterator(): # Using chunk_size here if you're working with Django >= 2.0 might help.
important_buildings = Building.objects.filter(
boundary__within=zip.boundary,
# Some conditions here ...

# You could even use annotations with conditional expressions
# as Case and When.

# Also Q and F expressions.

# It is very uncommon the use case you cannot address
# with Django's ORM.

# Ultimately you could use raw SQL. Anything to avoid having
# a list with the whole object.
)

# And then just load into the list the data you need
# to perform your analysis.

# Analysis according size.
data = important_buildings.values_list('size', flat=True)

# Analysis according height.
data = important_buildings.values_list('height', flat=True)

# Perhaps you need more than one attribute ...
# Analysis according to height and size.
data = important_buildings.values_list('height', 'size')

# Etc ...

请务必注意,如果您使用这样的解决方案,您只会在填充data 变量时访问数据库。当然,您只会在内存中拥有完成分析所需的最低限度。

提前思考。

当您遇到此类问题时,您应该开始考虑并行性、集群化、大数据等……另请阅读 ElasticSearch它具有非常好的分析能力。

演示

process.memory_info().rss 不会告诉您内存被释放。

我对你的问题和你在这里描述的事实很感兴趣:

It seems like the important_buildings list is hogging up memory, even after going out of scope.

的确,似是而非。看下面的例子:

from psutil import Process

def memory_test():
a = []
for i in range(10000):
a.append(i)
del a

print(process.memory_info().rss) # Prints 29728768
memory_test()
print(process.memory_info().rss) # Prints 30023680

所以即使释放了a内存,最后的数字还是更大。这是因为 memory_info.rss() 是进程 使用的总内存,而不是目前正在使用 的内存,如此处所述文档:memory_info .

下图是与之前代码相同但具有 range(10000000)

的图(内存/时间)

Image against time.我使用 memory-profiler 中的脚本 mprof对于这个图形生成。

您可以看到内存已完全释放,这不是您使用 process.memory_info().rss 进行分析时看到的情况。

If I replace important_buildings.append(building) with _ = building use less memory

永远都是这样,对象列表总是比单个对象使用更多的内存。

另一方面,您还可以看到使用的内存不会像您预期的那样线性增长。为什么?

来自这个优秀的site我们可以阅读:

The append method is “amortized” O(1). In most cases, the memory required to append a new value has already been allocated, which is strictly O(1). Once the C array underlying the list has been exhausted, it must be expanded in order to accommodate further appends. This periodic expansion process is linear relative to the size of the new array, which seems to contradict our claim that appending is O(1).

However, the expansion rate is cleverly chosen to be three times the previous size of the array; when we spread the expansion cost over each additional append afforded by this extra space, the cost per append is O(1) on an amortized basis.

速度很快,但有内存开销。

真正的问题不是Django 模型没有从内存中释放。问题是您实现的算法/解决方案,它使用了太多内存。当然,名单是反派。

Django 优化的黄金法则:尽可能替换查询集列表的使用。

关于python - 如何强制从内存中释放 Django 模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54152363/

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