以并行方式将`BufferedReader`转换为`Stream <string>`

时间:2015-05-12 16:10:08

标签: java java-8 bufferedreader java-stream

有没有办法从Stream<String> stream中接收BufferedReader readerstream中的每个字符串代表一行reader,附加条件为{{1}直接提供(在stream读取所有内容之前)?我希望处理reader平行的数据,以便从stream获取它们以节省时间。

编辑:我想处理与阅读并行的数据。我不想并行处理不同的行。它们应该按顺序处理。

让我们举例说明我希望如何节省时间。假设我们reader将向我们展示100行。读取一行需要2 ms,处理1 ms需要1 ms。如果我先读取所有行然后处理它们,将需要300毫秒。我想要做的是:一旦读取一行,我想处理它并且并行读取下一行。总时间将为201毫秒。

我不喜欢reader:据我所知,当我想处理这些线时,阅读就开始了。假设我已经拥有BufferedReader.lines(),但必须先进行预计算才能处理第一行。假设它们花费30毫秒。在上面的例子中,使用reader的总时间将是231毫秒或301毫秒(你能告诉我哪些时间是正确的吗?)。但是有可能在201毫秒内完成工作,因为预计算可以与读取前15行并行完成。

3 个答案:

答案 0 :(得分:7)

您可以使用reader.lines().parallel()。这样,您的输入将被拆分为块,并且将在块上并行执行进一步的流操作。如果进一步的操作需要很长时间,那么您可能会获得性能提升。

在您的情况下,默认启发式操作不会按您的意愿运行,我想没有现成的解决方案可以让您使用单行批处理。您可以编写一个自定义分裂器,它将在每行之后分割。查看java.util.Spliterators.AbstractSpliterator实施。可能最简单的解决方案是编写类似的内容,但将批量大小限制为trySplit中的一个元素,并在tryAdvance方法中读取单行。

答案 1 :(得分:2)

要做你想做的事,你通常会有一个线程读取行并将它们添加到阻塞队列,第二个线程将从这个阻塞队列获取行并处理它们。

答案 2 :(得分:2)

你看错了地方。您认为一行代码行将从文件中读取,但这不是它的工作原理。你不能告诉底层系统读取一条线,因为在阅读之前没有人知道一条线是什么。

BufferedReader有它的名字,因为它是字符缓冲区。此缓冲区的默认容量为8192.每当请求新行时,将解析缓冲区以获取换行序列,并返回该部分。当缓冲区没有足够的字符来查找当前行时,整个缓冲区将被填充

现在,填充缓冲区可能会导致请求从底层InputStream读取字节以填充字符解码器的缓冲区。将要请求的字节数和实际读取的字节数取决于字符解码器的缓冲区大小,实际编码映射到一个字符的字节数以及底层InputStream是否有自己的缓冲区和它有多大。

实际的昂贵操作是从底层流中读取字节,并且没有从行读取请求到这些读取操作的简单映射。请求第一行可能会导致读取,假设来自基础文件的一个16 KiB块,随后的100个请求可能从填充的缓冲区提供,并且根本不会导致I / O.您对Stream API所做的任何事情都无法改变这一点。您要并行化的唯一事情就是在缓冲区中搜索新的行字符,这对于并行执行来说太微不足道了。

您可以减少所有相关方的缓冲区大小,以便在处理前一行时粗略地获得一行的预期并行读取,但是,并行执行将永远不会补偿由小缓冲区大小引起的性能下降。