V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
liyifu1994
V2EX  ›  问与答

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

  •  
  •   liyifu1994 · 2022-07-09 11:47:48 +08:00 · 1797 次点击
    这是一个创建于 851 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

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

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

    最后,你真的搞明白 generator 了吗? range 的内部实现就是 generator
    liyifu1994
        6
    liyifu1994  
    OP
       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
        7
    liyifu1994  
    OP
       2022-07-10 09:59:58 +08:00
    @weiwoxinyou
    @winglight2016
    好像跟 jupyter 有关系。我用的是 vscode 和 jupyter interactive 去 print 数据,如果放在 CMD 里运行,是不会占用内存的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3123 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 13:45 · PVG 21:45 · LAX 05:45 · JFK 08:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.