为什么Java List遍历比文件readline慢?

时间:2014-08-10 18:32:23

标签: java algorithm arraylist

我有这段代码:

while((line=br.readLine())!=null)
        {
            String Words[]= line.split(" ");
            outputLine = SomeAlgorithm(Words);
            output.write(outputLine);
        }

正如您在上面的代码中所看到的,对于输入文件中的每一行,我正在读取一行,在其上运行一些算法,它基本上修改了该行,然后将输出行写入某个文件。

文件中有9k行,整个程序在我的机器上花了3分钟。

我想,好吧,我正在为算法的每次(直线)运行做2个I / O.所以我做了大约18k I / O.为什么不首先将所有行收集到ArrayList中,然后遍历列表并在每一行上运行算法?还要将每个输出收集到一个字符串变量中,然后在程序结束时写出所有输出一次。

这样,我整个程序总共有2个大I / O(18k小文件I / O到2个大文件I / O)。我认为这会更快,所以我写了这个:

List<String> lines = new ArrayList<String>();
while((line=br.readLine())!=null)
        {
            lines.add(line); // collect all lines first
        }

for (String line : lines){
    String Words[] = line.split(" ");
    bigOutput+=SomeAlgorithm(Words); // collect all output
}

output.write(bigOutput);

但是,这件事花了 7分钟 !!!

那么,为什么循环播放ArrayList比逐行读取文件要慢?

注意:通过readLine()收集所有行并写入bigOutput每个只需几秒钟。 SomeAlgorithm()也没有变化。所以,当然,我认为罪魁祸首是for (String line: lines)

更新:正如下面各种评论中所提到的,问题不在于ArrayList遍历,而是使用+ =累积输出的方式。转移到StringBuilder()确实给出了比原始结果更快的结果。

2 个答案:

答案 0 :(得分:3)

我怀疑性能的差异是由于你如何在一个变量(bigOutput)中收集输出。我的猜想是,这涉及大量的内存重新分配和字符数据的复制,这是缓慢的真正原因。

答案 1 :(得分:1)

这取决于文件的大小,但可能会发生的事情是,调整ArrayList存储空间并连接字符串需要的时间比执行大量小文件操作所需的时间长。

请记住,磁盘和操作系统都执行某种级别的I / O缓存,其中一些涉及预读(期望您可能会按顺序读取数据),因此第一次读取很可能将相当多的文件填入I / O缓存中,您可以从中快速读取。

因此,您需要从I / O缓存中进行小型读取,以获得平面阵列的许多调整(ArrayList和输出刺激),每次调整都变得越来越慢。

tl; dr version:让各种I / O缓存完成它们的工作。