Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Java列表遍历比文件读取线慢?_Java_Algorithm_Arraylist - Fatal编程技术网

为什么Java列表遍历比文件读取线慢?

为什么Java列表遍历比文件读取线慢?,java,algorithm,arraylist,Java,Algorithm,Arraylist,我有一段代码: while((line=br.readLine())!=null) { String Words[]= line.split(" "); outputLine = SomeAlgorithm(Words); output.write(outputLine); } 正如您在上面的代码中所看到的,对于输入文件中的每一行,我正在读取一行,在其上运行一些算法,基本上修改该行的读取,然

我有一段代码:

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);
List line=new ArrayList();
而((line=br.readLine())!=null)
{
行。添加(行);//首先收集所有行
}
用于(字符串行:行){
字符串字[]=行。拆分(“”);
bigOutput+=SomeAlgorithm(Words);//收集所有输出
}
output.write(bigOutput);
但是,这件事花了7分钟

那么,为什么在ArrayList中循环要比逐行读取文件慢呢?

注意:通过readLine()收集所有行并写入bigOutput只需几秒钟。SomeAlgorithm()也没有更改。所以,毫无疑问,我认为罪魁祸首是(字符串行:行)


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

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

这取决于文件的大小,但这里可能发生的情况是,调整
ArrayList
存储的大小和多次连接字符串所需的时间比执行许多小文件操作所需的时间更长

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

因此,您正在用从I/O缓存中读取的少量数据交换平面阵列的许多大小调整(ArrayList和output sting),这两种方法每次都变得越来越慢


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

构建结果的[string]
+=
可能是问题所在,而不是ArrayList。切换到StringBuilder,但最好使用缓冲输出。操作系统缓存的缓冲区输出将很好地处理此问题。尝试使用LinkedList?@mrVoid,即使列表是问题所在(可能不是,请参阅第一条注释)。尝试
新建ArrayList(10000)
,以避免
ArrayList
中的重新分配次数过多。使用缓冲读取器和缓冲写入器,这将极大地减少文件IO的数量,同时仍然允许您使用基本、简单的算法。准确地说,大量的重新分配和复制是由于它是如何累积的(string
+=
),而不是累积所固有的(
StringBuffer
)。@delnan是的,+=就是问题所在!我刚刚尝试了一个测试,将9000个大约100个字符串放入一个数组列表,耗时15毫秒。如果询问者在potatoArrayList上运行,那么您的答案可能完全正确。调整大小不应该是一个重要因素,特别是当它位于O(n²)字符串添加旁边时。由于大小呈指数增长,
ArrayList
增长不应该是这样的问题,我认为最大的问题是
+=
字符串连接,因此用
StringBuilder
替换它应该可以快速改进算法。还测试了大字符串连接,这在我的机器上花费了3.5秒。(9000行,每行100个字符)。与示例中几乎相同的代码+=是问题所在。我删除了它,并在每次运行算法后返回到编写输出,它只运行了2分30秒!