2

我正在处理一个需要处理大型 XML 文件的项目。在使用 Python 时,我不可避免地遇到了 Liza Daly 的文章http://www.ibm.com/developerworks/library/x-hiperfparse/。但是,我不明白她的 fast_iter 函数中的一行的细节:

def fast_iter(context, func):
    for event, elem in context:
        func(elem)
        elem.clear()
        while elem.getprevious() is not None:
            del elem.getparent()[0]
    del context

为什么使用 while 循环而不是 if 语句?怎么可能有不止一个先前的元素?

编辑:我忘了提到我只在一个我无法阅读的网站上看到了一个 if 版本,无论如何,http://jsome.net/blog/2010/08/18/handle-large-xml-with-python . 似乎几乎所有其他人都按原样使用 fast_iter。

如果我可以再问一个相关的问题......

对于我的项目,我发现只需添加 elem.clear() 即可将内存占用从 17+ GB 减少到 60 MB。进一步添加

while elem.getprevious() is not None:
    del elem.getparent()[0]

仅将其减少到 40 MB。我还没有将我的上下文保存在变量中,所以我还没有尝试添加“del context”。无论哪种方式,60 MB 和 40 MB 对我来说都可以忽略不计。我有理由继续添加有问题的代码吗?

    while elem.getprevious() is not None:
        del elem.getparent()[0]
del context

预先感谢您的帮助!

4

2 回答 2

2

我先回答你的第二个问题,因为它似乎更重要:

想象一下,您有一个包含 10000 个直接子树的节点。只是在elem.clear父节点完成之前,不会清理这些子树顶部的 10000 个节点。

如果您只有少数子树,这并没有太大的区别。(即使子树很深,每个子树都会clear随着它的进行而被编辑,所以只有每个子树的根存在。所以del elem.getparent()[0]不会那么重要。甚至可以想象,它对性能的伤害可能超过它有助于内存使用。因此,如果您知道要处理的 XML 类型,您可能希望以两种方式对其进行测试以查看。

但是如果你不知道你的代码将被调用来处理什么形状,那么可能值得删除之前的兄弟姐妹。


至于第一个问题:

我以前从未见过这篇博文,但我过去在两个项目中写过类似的代码,而且我从未使用过while. 事实上,这对我来说似乎有点笨拙——你不需要在两个事件上都start这样做;end只需删除前一个孩子 on start,或者更简单地说,删除自己 on end,对吗?

但该博客文章可能试图尽可能笼统。一方面,context可能是一个iterparsethat give onlystart或 only end,对吗?同时,func可能是某种东西在飞行中使树发生变异。我有两个项目在运行时对树进行变异iterparse,虽然它们都不需要这个循环,但这只是因为它们中的一个碰巧插入到之后而不是之前。

正如 user1093967 指出的那样,lxml 文档部分修改树解释了一个场景,您可能希望使用while而不是if:如果您扩展代码以过滤搜索,您可能有多个已跳过的兄弟姐妹。

无论如何,与前一种情况不同,这里使用while而不是if,或者同时检查start和并没有真正的成本end,所以你最好坚持使用完全通用的解决方案。

于 2013-10-26T00:57:34.290 回答
0

您可以通过在循环中添加 a 并查看每个节点print elem.getprevious() is not None是否获得多个来轻松地自己找出答案。True

但是,即使在您的应用程序中while循环不是必需的,也有func()可能添加节点,所以......比抱歉更安全。出于同样的原因,我假设,她getparent()每次都通过循环调用,而不是在进入循环之前存储父级,而只是在循环体中引用它,这样会更快……func()理论上可以改变父级。

如果额外的内存不是问题,我不会打扰。执行更多的 Python 代码比执行更少的代码要慢。

顺便说一句,假设Element该类具有与 Python 列表相似的存储特性,从性能的角度来看,每次通过循环删除第一个子元素可能不是最佳的。您是否注意到将取决于您的文档,但是以相反的顺序迭代它们并删除下一个节点而不是以前的节点可能会稍微快一些,假设顺序无关紧要(或者之后可以很容易地更正)。

于 2013-10-26T00:54:26.847 回答