【问题标题】:Python on Windows. Why is reading text 8x slower than binary?Windows 上的 Python。为什么阅读文本比二进制慢 8 倍?
【发布时间】:2017-11-17 16:12:55
【问题描述】:

我在 Windows 10(均为 64 位)上运行 python 3.6,具有快速 SSD、32GB RAM 和非常快的处理器(AMD Threadripper)。我在 Intel i7 上也得到了类似的结果。我正在打开大小约为 5MB 的 XML 文本文件,发现即使使用 lxml 性能也很慢。我将问题归结为磁盘读取性能。如果我加载为二进制文件,速度会快 8 倍以上。以下测试是使用已在磁盘缓存中的文件执行的。在这些运行过程中,磁盘从未被击中。冷读也得到了类似的结果。

%%timeit
with open(xmlpath + fn, 'rb') as f:
    r = f.read()
1.66 ms ± 31.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%%timeit
with open(xmlpath + fn, 'r', encoding='UTF-8') as f:
    r = f.read()
13.7 ms ± 32.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

我知道必须为文本版本处理编码,但是在快速处理器上运行时慢 8 倍似乎过度。此外,1.6ms 对我来说读取缓存中已经存在的这么小的文件似乎很慢。使用 Passmark 测量的磁盘性能符合预期 > 2GB/s。

任何意见/建议将不胜感激。谢谢。

【问题讨论】:

    标签: python windows python-3.x performance


    【解决方案1】:

    当您使用rb 时,可以直接在最终缓冲内存 (r) 中以无限/非常大的块大小读取文件。

    当您使用r 时,必须以较小的块大小读取文件,以便能够对块进行后处理并删除\n 字符之前的\r 字符(如果不是逐个字符完成,这将是最简单但最慢的方法)

    如果你有能力复制内存(r 模式不这样做),我建议:

    with open(xmlpath + fn, 'rb') as f:
        r = f.read().decode('UTF-8').replace('\r','')
    

    还保存解码和替换,如 cmets 所述:

    with open(xmlpath + fn, 'r', newline="") as f:
        r = f.read()
    

    【讨论】:

    • 感谢您的快速回复。我尝试了您的建议并得到:每个循环 12.4 ms ± 160 µs(平均值 ± 标准偏差。7 次运行,每次 100 个循环)。这似乎仍然过分。
    • UTF-8 是 ASCII 的超集,因此您可以安全地替换 bytes 对象而不是解码的字符串。这应该可以节省几毫秒的时间。但是替换操作仍然是性能瓶颈——比解码更严重。不可能在纯 Python 级别对此进行优化。如果您可以忍受内存中的 CRLF 行结尾,那么 newline='' 是性能和内存之间的良好折衷。
    • @eryksun 好点。添加。我对这种二进制/非二进制的个人经验是写入网络磁盘。性能差异从 10 秒到 3 分钟,可能是因为块大小不同。
    • 如果缓冲区大小是问题,为什么不使用第三个参数buffering 代替open?此外,在 Python 3 上,它绝对不仅仅是换行符被转换,它必须转换为核心字符串类型,这取决于遇到的字符将具有不同的格式(请参阅PEP 393)。如果内部格式与文件编码匹配,则可能会进行优化。
    • 缓冲,值得一试。
    猜你喜欢
    • 1970-01-01
    • 2015-08-03
    • 2021-05-30
    • 2015-02-20
    • 1970-01-01
    • 1970-01-01
    • 2011-01-10
    • 1970-01-01
    • 2014-10-04
    相关资源
    最近更新 更多