保持文件句柄打开的弊端?

时间:2018-06-25 14:44:53

标签: python python-3.x performance file-handling

我正在解析一些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 个答案:

答案 0 :(得分:2)

您已经提到的明显的缺点是,保持所有文件句柄打开需要大量内存,具体取决于多少个文件。这是您必须自己进行的计算。并且不要忘记写锁。

否则,每个人说的话并没有多大错,但是一定要做好一些预防措施:

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中遍历字典时,您获得的项实际上只是键。我建议您进行for key, item in d.items():for item in d.values():

答案 1 :(得分:1)

不要没有说出该过程最终将打开多少个文件。如果不是很多那么多问题,那么这可能是一个好方法。我怀疑您是否真的可以在不对数据和执行环境中进行尝试的情况下就知道了。

根据我的经验,open()相对较慢,因此避免不必要的调用绝对值得考虑-您还避免设置所有关联的缓冲区,填充它们,在每次关闭文件时刷新它们,以及垃圾收集。如您所愿,文件指针确实带有大缓冲区。在OS X上,默认缓冲区大小为8192字节(8KB),并且与所有Python对象一样,该对象还有额外的开销。因此,如果您有成百上千的文件和很少的RAM,则可以累加起来。您可以指定更少的缓冲或根本不指定缓冲,但这可能会降低避免重复打开的效率。

编辑:对于35个不同的文件(或任何两位数字),您无需担心:35个输出缓冲区将需要的空间(实际每个缓冲区需要8 KB)缓冲)甚至不会占您内存占用的最大部分。因此,只要按照您的建议去做就可以了。与打开和关闭每个xml节点的文件相比,您将看到速度的显着提高。

PS。默认缓冲区大小由io.DEFAULT_BUFFER_SIZE给出。

答案 2 :(得分:0)

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

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

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

答案 3 :(得分:-1)

如果要以成批方式编写成千上万个文件 它们到目录结构中以使其分别存储在不同的位置 目录以方便以后访问。例如:a / a / aanode.txt,a / c / acnode.txt等。

如果XML包含连续的节点,您可以在 条件为真。仅在出现另一个文件的另一个节点时关闭。 从中获得的收益很大程度上取决于XML文件的结构。