代码之家  ›  专栏  ›  技术社区  ›  Bram Vanroy

保持文件句柄打开的缺点?

  •  1
  • Bram Vanroy  · 技术社区  · 6 年前

    我正在解析XML,并根据当前正在处理的XML元素,将数据写入不同的文件。处理一个元素真的很快,而且编写数据也是如此。因此,文件需要经常打开和关闭。例如,假设 file 以下内容:

    for _, node in lxml.etree.iterparse(file):
        with open(f"{node.tag}.txt", 'a') as fout:
            fout.write(node.attrib['someattr']+'\n'])
    

    这是可行的,但相对而言,打开和关闭文件需要很多时间。(注:这是一个玩具程序。实际上,我写入文件的实际内容和文件名是不同的。有关数据的详细信息,请参见最后一段。)

    另一种选择是:

    fhs = {}
    for _, node in lxml.etree.iterparse(file):
        if node.tag not in fhs:
            fhs[node.tag] = open(f"{node.tag}.txt", 'w')
    
        fhs[node.tag].write(node.attrib['someattr']+'\n'])
    
    for _, fh in fhs.items(): fh.close()
    

    这将保持文件打开,直到XML解析完成。有一点查找开销,但与迭代打开和关闭文件相比,应该是最小的。

    我的问题是,从性能角度看,这种方法的缺点是什么?我知道这会使打开的文件无法被其他进程访问,并且可能会遇到。 a limit of open files .不过,我对性能问题更感兴趣。保持所有文件句柄打开会产生某种内存问题或处理问题吗?在这种情况下,文件缓冲可能太多了?我不确定,所以这个问题。

    输入的xml文件最多可达70gb左右。生成的文件数量限制在35个左右,这与我在上述文章中看到的限制相去甚远。

    4 回复  |  直到 6 年前
        1
  •  1
  •   alexis    6 年前

    不要 并没有说这个过程最终会有多少文件打开。如果不是太多导致了问题,那么这可能是一个很好的方法。我怀疑如果不在数据和执行环境中尝试它,您是否真的可以知道。

    以我的经验, open() 是比较慢的,所以避免不必要的调用是绝对值得思考的——也避免设置所有相关的缓冲区,填充它们,每次关闭文件时清理它们,然后进行垃圾回收。既然你这么问了,文件指针确实有很大的缓冲区。在OSX上,默认的缓冲区大小是8192字节(8KB),并且对象有额外的开销,就像所有的Python对象一样。所以如果你有成百上千的文件和小内存,它可以加起来。您可以指定更少的缓冲或根本不进行缓冲,但这可能会破坏避免重复打开所获得的任何效率。

    编辑: 对于35个不同的文件(或者任何两个数字),你没有什么可担心的:35个输出缓冲区所需的空间(实际缓冲区的缓冲区为8 kb)甚至不会成为内存占用的最大部分。所以就按照你的建议去做吧。与打开和关闭每个xml节点的文件相比,您将看到显著的速度改进。

    ps.默认缓冲区大小由 io.DEFAULT_BUFFER_SIZE 是的。

        2
  •  2
  •   Pax Vobiscum    6 年前

    你已经提到的明显缺点是,要保持所有文件句柄打开,需要多少内存,当然取决于有多少文件。这是一个你必须自己做的计算。别忘了写锁。

    否则,每说一句话都不会有太大的错误,但如果采取一些预防措施,那就好了:

    fhs = {}
    try:
        for _, node in lxml.etree.iterparse(file):
            if node.tag not in fhs:
                fhs[node.tag] = open(f"{node.tag}.txt", 'w')
    
            fhs[node.tag].write(node.attrib['someattr']+'\n'])
    finally:
        for fh in fhs.values(): fh.close()
    

    注: 在python中循环dict时,得到的项实际上只是键。我建议你 for key, item in d.items(): for item in d.values():

        3
  •  0
  •   Enthusiast Martin    6 年前

    作为一个好的规则,尝试尽快关闭一个文件。

    请注意,您的操作系统也有限制-您只能打开特定数量的文件。因此,您可能很快就会达到这个限制,并开始出现“无法打开文件”异常。

    内存和文件句柄泄露是明显的问题(如果由于某种原因无法关闭文件)。

        4
  •  -1
  •   hootnot    6 年前

    如果你正在生成数以千计的文件,你可以考虑写 将它们分别存储在不同的目录结构中 目录以便以后更容易访问。例如:a/a/aanode.txt、a/c/acnode.txt等。

    如果xml包含连续的节点,则可以在 条件是真的。只在另一个文件的节点出现时关闭。 从中获得的好处很大程度上取决于XML文件的结构。