【问题标题】:What would be the fastest way to read integers from a file in Java?从 Java 文件中读取整数的最快方法是什么?
【发布时间】:2011-05-24 17:53:53
【问题描述】:

我有一个这样排列的整数文件:

1 2 3 55 22 11 (and so on)

我想尽可能快地读入这些数字,以减少我的程序的总执行时间。到目前为止,我使用的扫描仪效果很好。但是,我感觉存在一个可以使用的更快的 IO 实用程序。谁能指出我正确的方向?

编辑:

所以是的,我通过围绕 java 代码设置不同的计时器并比较结果来验证程序中的 IO 花费的时间最多。

【问题讨论】:

  • 如果您已经获得“好结果”,为什么还需要“最快”的方式?您的程序是否需要很长时间才能执行?
  • 在开始优化之前,我建议您使用分析器(例如 YourKit)来确定这部分代码确实是整体瓶颈。如果不是,您将浪费时间优化它。
  • 这些值是典型的吗?总是正数,总是在字节范围内,总是低于 100?它们会被用作字节、短裤、整数还是长整数?

标签: java performance io


【解决方案1】:

当前文件格式

如果数字表示为Strings,则没有更快的方法来读取和解析它们,磁盘 I/O 将比 CPU 正在执行的任何操作慢几个数量级。唯一能做的就是使用具有巨大缓冲区大小的BufferedReader,并在使用Scanner 之前尝试尽可能多地获取内存中的文件。

替代文件格式

如果您可以在文件中将它们表示为二进制文件并使用DataInputStream class 读取数字,那么您可能会在 I/O 时间和 CPU 上略微减少,因为您不需要将String 表示解析为int,除非您的输入文件为数百兆字节或更大,否则这可能无法测量。 **缓冲输入流仍然比其他任何东西都更有效果,在这种情况下使用BufferedInputStream

如何优化

您需要可靠的分析来检测您所做的任何更改是正面还是负面影响性能。

如果您一遍又一遍地读取同一个文件,操作系统磁盘缓存之类的东西会扭曲基准测试,操作系统会缓存它并搞砸您的基准测试。尽早了解什么是足够好

“我们应该忘记小 效率,说大约 97% 时间:过早优化是 万恶之根”——Donald Knuth

Kunth 引用的过早部分是重要的部分,它的意思是:

不要在没有分析和基准的情况下进行优化,以验证您所做的更改实际上是一个瓶颈,并且您可以衡量更改的积极或消极影响。

Here is a quick benchmark 比较读取同一组二进制数的BufferedInputStream 与由BufferedReader 支持的Scanner 读取同一组数字作为带有SPACE 分隔符的文本表示。

结果非常一致:

在配备 8GB RAM 的 Core i3 笔记本电脑上处理 1,000 个号码

Read binary file in 0001 ms
Read text file in   0041 ms

在配备 8GB RAM 的 Core i3 笔记本电脑上处理 1,000,000 个号码

Read binary file in 0603 ms
Read text file in   1509 ms

在配备 8GB RAM 的 Core i3 笔记本电脑上处理 50,000,000 个号码

Read binary file in 29020 ms
Read text file in   70346 ms

50,000,000 个号码的文件大小如下:

 48M input.dat
419M input.txt

在数字集变得非常大之前,读取二进制文件的速度要快得多。二进制编码整数上的 I/O 更少(大约 10 倍),没有 String 解析逻辑,以及对象创建的其他开销以及 Scanner 所做的任何其他事情。我继续使用Buffered 版本的InputStreamReader 类,因为这些是最佳实践,应尽可能使用。

对于额外的功劳,压缩将进一步减少大文件上的 I/O 等待,而对 CPU 时间几乎没有可测量的影响。

【讨论】:

  • 其实我不认为这个问题是IO绑定的。我刚刚运行了一个小测试,扫描了一个包含正随机数 gist.github.com/989397 虽然当然可以调整一些参数,但很明显这个问题不受 IO 限制。 (如果您发现我的测试有问题,请告诉我)
  • 华夫饼样本个数都小于100,所以一个数字加上一个分隔符用了3个字节。小于 100 的数字完全适合单个字节,但它们总是适合一个字节?这些数字是否具有代表性?您是否使用整数进行读取,二进制占用 4 个字节?不同的假设带来不同的测量结果。如果大多数数字都小于 100,但它们都应用作 int,则将它们作为文本读取将需要较小的文件来读取。
  • 字符串99 加上分隔符的空格如何适合“单字节”?它还需要被解析成原始的 int 表示形式。
【解决方案2】:

通常,您可以在磁盘允许的范围内尽可能快地读取数据。更快地阅读它的最佳方法是使其更紧凑或获得更快的磁盘。

对于您使用的格式,我会将文件 GZip 并读取压缩数据。这是提高基础数据读取速度的简单方法。

【讨论】:

    【解决方案3】:

    升级可能性:

    • 购买速度更快的磁盘。
    • 购买固态硬盘。
    • 将文件存储在 ramdisk 中。

    在获得更多性能/速度方面总是需要权衡取舍。上述方法要花钱,而且必须在每台主机上执行,所以如果这是一个出售给多个客户的程序,那么在算法上玩弄算法可能是一个更好的选择,这样可以在每台主机上节省资金,程序正在运行。

    如果压缩文件或存储二进制数据,读取速度会提高,但使用独立工具检查数据会更加困难。当然,我们无法确定这种情况发生的频率。

    在大多数情况下,我会建议保留人类可读的数据,并使用较慢的程序,但这当然取决于您丢失了多少时间,丢失的频率等等。

    也许这只是一个练习,以找出你能跑多快。但是,我想提醒大家不要养成在不考虑权衡和成本的情况下始终达到最高性能的习惯。

    【讨论】:

      猜你喜欢
      • 2011-10-26
      • 1970-01-01
      • 1970-01-01
      • 2020-10-06
      • 1970-01-01
      • 2013-10-24
      • 2021-12-08
      • 2011-08-11
      • 1970-01-01
      相关资源
      最近更新 更多