【问题标题】:Speed up writing to files加快写入文件的速度
【发布时间】:2011-06-25 02:21:52
【问题描述】:

我已经分析了一些我使用 cProfile 继承的遗留代码。我已经做出了很多有用的更改(比如使用 simplejson 的 C 扩展!)。

基本上,此脚本将数据从一个系统导出到 ASCII 固定宽度文件。每一行都是一条记录,它有很多值。每行有 7158 个字符,包含大量空格。总记录数为 150 万条记录。每行一次生成一个,需要一段时间(每秒 5-10 行)。

在生成每一行时,它会尽可能简单地写入磁盘。分析表明,大约 19-20% 的总时间花费在 file.write() 上。对于 1,500 行的测试用例,需要 20 秒。我想减少这个数字。

现在看来,下一个胜利将是减少写入磁盘所花费的时间。如果可能的话,我想减少它。我可以在内存中保留记录的缓存,但我不能等到最后一次全部转储。

fd = open(data_file, 'w')
for c, (recordid, values) in enumerate(generatevalues()):
        row = prep_row(recordid, values)
        fd.write(row)
        if c % 117 == 0:
                if limit > 0 and c >= limit:
                        break
                sys.stdout.write('\r%s @ %s' % (str(c + 1).rjust(7), datetime.now()))
                sys.stdout.flush()

我的第一个想法是将记录缓存保存在列表中并分批写出。那会更快吗?比如:

rows = []
for c, (recordid, values) in enumerate(generatevalues()):
        rows.append(prep_row(recordid, values))
        if c % 117 == 0:
            fd.write('\n'.join(rows))
            rows = []

我的第二个想法是使用另一个线程,但这让我想死在里面。

【问题讨论】:

  • 应用的瓶颈是什么?
  • 我以为我很清楚。它花费 20% 的时间一次写入磁盘一行。
  • 那么,进行更改和配置文件吗?预计它不会产生什么影响,因为文件 I/O 通常是行缓冲的......或者我认为是这样。
  • 线程不会有帮助。你怎么这么潮。我的意思是我知道勒布朗詹姆斯“永远不会忘记刷新”,但是你每次写到标准输出时都需要这样做吗?
  • @David,刷新是为了他的标准输出,而不是有问题的文件。

标签: python performance file-io


【解决方案1】:

实际上,您的问题不在于file.write() 占用了您 20% 的时间。 80% 的时间你都不在file.write()

写入磁盘很慢。你真的无能为力。将内容写入磁盘仅需要大量时间。您几乎无法做任何事情来加快速度。

您希望 I/O 时间成为程序的最大部分,这样您的速度就会受到硬盘速度而不是处理时间的限制。 file.write() 的理想状态是 100% 使用!

【讨论】:

  • +1,通常我会同意你的看法。但是在这种情况下,我用来生成数据的外部过程非常慢,我想尽可能地减少其他一切。我想我应该在几秒钟内说话,并专注于减少它。将编辑以澄清秒数。
  • 已更新以指定写入 1,500 条记录需要 20 秒。我真的很在乎这个数字,我只是用百分比来证明它确实值得优化。
  • @chmullig,等待外部进程花费的百分比是多少?
  • ~53% 用于等待外部进程。另外约 3% 用于一些标头类型的函数。 14% 用于 simplejson loading() 20% 用于 IO。所以只有 10% 是我的代码。
  • @chmullig,这里有点不对劲。写作不可能花那么长时间。看看python程序是否可以更快地将其他随机字符串写入磁盘。
【解决方案2】:

将写入分批成 500 组确实确实显着加快了写入速度。对于这个测试用例,单独写入行在 I/O 中花费了 21.051 秒,而以 117 为单位写入需要 5.685 秒来写入相同数量的行。 500 个批次总共只用了 0.266 秒。

【讨论】:

  • 现在您可以为文件写入添加线程以进行异步写入
  • 更好 - 只需输出到标准输出,将其通过管道传输到文件,然后让操作系统为您进行缓冲和批量写入。 :)
  • @LesterCheung,你能详细说明一下吗?
  • @blindguy like "python yourprog.py | buffer > out" 但我认为批处理输出在这里仍然会有所帮助。
  • 性能与他的方法相比如何?操作系统缓冲一样快吗?
【解决方案3】:

您可以在 python 中执行mmap,这可能会有所帮助。但我怀疑你在分析时犯了一些错误,因为 20 秒内的 7k * 1500 大约是 0.5 Mbytes/s。做一个测试,你随机写相同长度的行,你会发现它比这快得多。

【讨论】:

    猜你喜欢
    • 2015-04-19
    • 2020-02-06
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    • 2019-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多