【问题标题】:How to reading Java (Using Java lib in Scala) InputStream efficiently?如何有效地阅读 Java(在 Scala 中使用 Java 库)InputStream?
【发布时间】:2022-01-24 12:19:22
【问题描述】:

我的 Scala 服务器通过socket.getInputStream 从套接字获取InputStream 对象(从我的套接字客户端发送的一些字节,字节的大小打印在下面)

下面的代码尝试将其读入数组

  var buffer: Array[Byte] = null
  def read(stream: InputStream, size: Int) = {
    val start = System.nanoTime()
    buffer = new Array[Byte](size)
    var value: Int = 0
    (0 until size).foreach(i => {
      value = stream.read()
      buffer(i) = value.toByte
    })
    val end = System.nanoTime()
    println(s"Getting buffer from InputStream, size: $size, cost: ${(end - start)/1e6} ms")
    buffer
  }

部分输出是

Getting buffer from InputStream, size: 4, cost: 174.923596 ms
Getting buffer from InputStream, size: 2408728, cost: 919.207885 ms

但是,对于相同的数据大小,一些现有的服务器可能会更快,例如Redis 可以在 ~10ms 内发送字节,所以

是否可以提高此程序的性能?

【问题讨论】:

  • 为什么不使用像 Fs2AkkaStreams 这样的高级库?甚至,如果您想阅读所有内容,您可以使用标准库中的Source

标签: java scala inputstream bufferedreader


【解决方案1】:

stream.read() 是对这个概念的最慢理解。

相反,您需要read(byte[]) 变体或read(byte[], int offset, int length) 变体(一个非常简单且性能方面基本上免费的 3 参数方法包装器)。

使用read() 的“开销”从“轻微”(如果涉及缓冲区)到“1000 倍”(如果没有缓冲区)不等。如果是第二个,您可以通过将输入流包装在 BufferedInputStream 中并从中读取来回到“轻微”开销。

但不管发生什么,这个:

int toRead = 1000;
byte[] data = new byte[toRead];
int readSoFar = 0;
while (readSoFar < toRead) {
  int read = in.read(data, readSoFar, toRead - readSoFar);
  if (read == -1) throw new IOException("Expected more data");
  toRead += read;
}

快:

int toRead = 1000;
byte[] data = new byte[toRead];
while (toRead > 0) {
  data[toRead--] = in.read();
}

使用 scala 对这些示例的性能没有影响。

【讨论】:

  • 在代码中我使用一次读取单个字节,但从源代码 (InputStream.java) 我看到读取字节数组是读取单个字节的 for 循环。无论如何,我做了一些搜索,人们说读取数组要快得多。是不是我对源码的理解错了?
  • 是的,读取整个字节数组要快得多——我的(这个)答案也是这么说的。
  • 哦,是的,我发现只有InputStream 基类使用循环读取数组。并且子类在大多数情况下使用 memcpy
猜你喜欢
  • 1970-01-01
  • 2011-06-29
  • 2013-08-19
  • 2021-01-16
  • 2023-04-06
  • 2021-07-30
  • 2016-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多