坛子里大神多,我想问个 Python 内存占用的问题

2022-07-09 11:47:48 +08:00
 liyifu1994

最近在在处理 XML 文件,一个就十几个 G ,很容易爆内存。我是用的 generator 爬取 XML 的,按理说不应该每一步之后,自动清理 element 的内存,内存中每次只保存一个 element 吗?于是联想到一个问题

for i in range(10**20): s = i + 10

range 函数本身就是生成器,为什么做上面的计算,内存占用就几乎不会变动,但是如果改成下面的代码:

for i in range(10**20): print(i)

内存很快就爆了 想请教大佬们,这二者有什么区别呢?谢谢大家!

1603 次点击
所在节点    问与答
7 条回复
westoy
2022-07-09 11:50:00 +08:00
下面的有 IO 输出
liyifu1994
2022-07-09 11:54:17 +08:00
@westoy 谢谢大佬,爬取 XML 文件的时候,也需要 append 到 list ,所以就需要手工清理一遍,也就是 elem.clear()。只有不输出的话,generator 相对于 list 的优势才是内存管理,我理解的对吧?
haoliang
2022-07-09 12:19:59 +08:00
我不相信 `for i in range(10**20): print(i)` 会占满内存。尽管 sys.stdout 是 buffered ,但 buffer 一般也就 8k
weiwoxinyou
2022-07-09 23:31:36 +08:00
如#3 所说,单纯 `print` 不会导致内存占满,我感觉你需要检查的是是不是一直对同一个列表或其他变量填充数据且不断进行变量新增,建议放完整代码。
题中两者区别是是否存在 IO ,但是 Python 默认采用单线程,所以第二个会慢一点,但是绝不会因此导致内存占满。
winglight2016
2022-07-10 07:13:02 +08:00
generator 不是万能药。read file line by line 只是保证文件不是一次性读取到内存,你还得确保没有用全局变量保存在内存,同时写入文件的对象也不是整个文件。

最后,你真的搞明白 generator 了吗? range 的内部实现就是 generator
liyifu1994
2022-07-10 09:48:17 +08:00
完整代码如下:


def parse_and_remove(filename, path):
path_parts = path.split('/')
doc = iterparse(filename, ('start', 'end'))
# Skip the root element
next(doc)

tag_stack = []
elem_stack = []
for event, elem in doc:

if event == 'start':
tag_stack.append(elem.tag)
elem_stack.append(elem)
elif event == 'end':
if tag_stack == path_parts:
yield elem
elem.clear() ##这里加上 elem.clear(),内存占用几乎不变,可以完成任务;如果去掉的话,内存占用会越来越大直至 crash

try:
tag_stack.pop()
elem_stack.pop()
except IndexError:
pass


def count_stats(filepath, filename):
start = time.time()
print('\nStart processing file ', filepath)
data = parse_and_remove(filepath, 'Job')

results = []
count = 1

for job_node in data:
continue ##即使这里什么都不做,内存占用也会越来越大


print 的程序如主楼所示。内存占用越来越大直至 crash




谢谢二位

@winglight2016
@weiwoxinyou
liyifu1994
2022-07-10 09:59:58 +08:00
@weiwoxinyou
@winglight2016
好像跟 jupyter 有关系。我用的是 vscode 和 jupyter interactive 去 print 数据,如果放在 CMD 里运行,是不会占用内存的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/865084

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX