- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我想使用管理命令对马萨诸塞州的建筑物进行一次性分析。我已将有问题的代码缩减为 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
会有所帮助(请注意 iterator
的 chunk_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)
我使用 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/
我对 Python-Django 和 web 开发还很陌生,我被困在这个使用 POST 创建新资源的特殊问题上。 我正在为 REST API 使用 Django REST 框架,我正在尝试创建一个新资
我已经使用 Django-storages 成功地将 Word 文档存储到 S3。 class Document(TitleSlugDescriptionModel, TimeStampedModel
我有 2 个关于模型代理的问题, 如何从模型对象创建代理对象? 如何从模型查询集创建代理查询集? 例如,假设我们定义了: from django.contrib.auth.models import
我想编写一个直接执行 HTTP 请求的单元测试(而不是使用 django.test.client.Client)。 如果您好奇为什么 - 那是因为我想测试我从 Django 应用程序公开的 Thrif
我为我的个人网站启动了一个 django 项目来学习 django。到目前为止,我已经将我的开发环境设置为我需要的一切,并遵循 this很棒的教程来创建一些基本的数据结构和模板。现在我想开始使用我之前
我已经阅读了很多关于如何在使用 Django 注册时添加额外字段的信息,例如 here 、 here 和 here 。代码片段是: forms.py(来自注册应用程序) class Registrat
我正在编写小型社交应用程序。功能之一是在网站标题中写入用户名。因此,例如,如果我登录并且我的名字是Oleg(用户名),那么我应该看到: Hello, Oleg | Click to edit prof
我有一个使用 Django 和 Django Rest 框架开发的应用程序。我想将 django-reversion 功能添加到我的应用程序中。 我已经尝试过http://django-reversi
我有一个简单的 HTML 表单,我没有使用 Django 表单,但现在我想添加一个选择。 选择最容易创建为 Django ChoiceField (与通过循环等手动创建选择相反),但是,如果没有在 D
我不明白为什么人们以两种方式编写外键,这样做的目的是什么?它们是相同还是不同? 我注意到有些人这样写: author = models.ForeignKey(Author, on_delete=mod
我想在我的 Django 应用程序中获取评论最多的十个帖子,但我做不到,因为我想不出合适的方法。 我目前正在使用 django 评论框架,并且我已经看到使用 aggregate or annotate
这对于 Django 1.2 仍然有效吗? Custom Filter in Django Admin on Django 1.3 or below 我已经尝试过,但管理类中的 list_filter
问题在于,当 django-compressor 编译为 .js 文件的 CoffeeScript 文件中引用 {{ STATIC_URL }} 时,它无法正确加载。 在我的 django 模板中,我
我正在尝试将一些字段从一个 django 模型移动到一个新模型。假设我有一个书籍模型: class Book(models.Model): title = models.CharField(max
我想在我的 Django 应用程序中获取评论最多的十个帖子,但我做不到,因为我想不出合适的方法。 我目前正在使用 django 评论框架,并且我已经看到使用 aggregate or annotate
目前我正在寻找在 Django 中实现访问控制。我已经阅读了有关内置权限的内容,但它并不关心每个对象的基础。例如,我想要“只有创建者可以删除自己的项目”之类的权限。所以我读到了 django-guar
嗨,我正在将我的 Django 模型的一个字段的值设置为其他模型的另一个字段的值。这个值应该是动态变化的。 这是我的第一个模型 class MainModel(AbstractBaseUser, Pe
我正在尝试为我的模型创建一个编辑表单。我没有使用模型表单,因为根据模型类型,用户可以使用不同的表单。 (例如,其中一个表单有 Tinymce 小部件,而另一个没有。) 有没有什么方法可以使用模型设置表
Django 模板中的搜索字段 如何在类似于此图像的 Django 模板中创建搜索字段 http://asciicasts.com/system/photos/1204/original/E354I0
根据 Django documentation ,如果 Django 安装激活了 AuthenticationMiddleware,HttpRequest 对象有一个“user”属性代表当前登录的用户
我是一名优秀的程序员,十分优秀!