为什么file.close()会减慢我的代码

时间:2016-09-08 13:34:47

标签: python performance io

我正在编写一个程序,它生成指定数量的句子,每个句子都写入一个文件。我一直在尝试为1000万句或更多句子的案例优化代码。

我最近在打开调用中将缓冲区参数指定为512MB以提高写入性能,但是我的代码实际上慢了3秒。罪魁祸首是{method 'close' of '_io.TextIOWrapper' objects}。我认为这与文件关闭方法有关,但这是我第一次比较配置文件输出。

这是我的写入速度有多慢:

10000000   49.057    0.000   49.057    0.000 {method 'write' of '_io.TextIOWrapper' objects}

现在就是这样:

10000000    3.184    0.000    3.184    0.000 {method 'write' of '_io.TextIOWrapper' objects}

相当大的改进。

这是我以前的近距离方法:

3    4.003    1.334    4.003    1.334 {method 'close' of '_io.TextIOWrapper' objects}

这是我的新人:

 1   62.668   62.668   62.668   62.668 {method 'close' of '_io.TextIOWrapper' objects}

这是我的代码:

def sentence_maker(nouns, verbs, number_of_sentences, file_name):
    writer = open(file_name, "w", 536870912)
    for num in range(number_of_sentences):
        string = (choice(nouns) + " " + choice(verbs) + " " + choice(nouns))
        writer.write(string + "\n")
    writer.close()

为什么close()这么慢?

注意:在程序早期的某个地方,我曾经有一些close()语句,因此在我的旧ncalls = 3示例中为close()。我已经确定这些对性能没有明显的影响。

2 个答案:

答案 0 :(得分:1)

写入磁盘的速度很慢,因此许多程序将写入存储到大块中,这些块一次性写入。这称为缓冲,Python在您打开文件时会自动执行此操作。当您写入文件时,您实际上正在写入"缓冲区"在记忆中。当它填满时,Python会自动将其写入磁盘或调用close()。

答案 1 :(得分:1)

你明确选择使用一个巨大的缓冲区(536870912是在刷新缓冲区之前缓冲的字节数,大约半GB的内存)。 close包含隐含在缓冲区中的任何内容flush,并假设您正在写很多内容,这意味着它需要全部写出来。

您必须在某个时候支付实际的I / O;一个大的缓冲区使得write便宜(因为它实际上并没有执行任何I / O),但是一个大的缓冲区只是推迟了痛苦,而不是避免它。我怀疑任何超过1 MB的缓冲区大小实际上会节省有意义的工作(并且限制可能更低);如果你经常这样做,执行系统调用的成本很高,但是当每次调用完成的工作(实际的物理I / O)超过它们时,每MB一次调用和每512 MB一次调用之间的差异是没有意义的。一个数量级或更多。

为了进行比较,缓冲的原因是系统调用与常规函数调用(a few hundred clock ticks, vs. a dozen or less for most function calls)相比具有较高的开销。 CPython在I / O中有一些额外的系统调用(释放和恢复GIL),因此系统调用writememcpy的增量成本相差100-1000x。但即使在现代CPU的开销上,即使2000个滴答仍然在微秒范围内。但是I / O本身要贵得多;写10 MB的数据可能需要十分之一秒左右。 使用较大的缓冲区大小在系统调用上保存一些毫秒并不重要,当I / O本身的成本在中测量时。一个缓冲区,大的将开始引入缓存未命中(以及可能的页面错误),较小的缓冲区将避免。