【问题标题】:Byte array outputstream [closed]字节数组输出流[关闭]
【发布时间】:2020-11-24 10:45:30
【问题描述】:

可能是一个愚蠢的问题,但是通过outputstream 发送的字节数组的理想长度是多少?我在网上找不到任何关于此的内容。

我发现了很多将它们的数组大小设置为 2^X 或类似值的示例。但是这样做的目的是什么?

【问题讨论】:

    标签: java arrays byte outputstream


    【解决方案1】:

    没有最佳尺寸。 OutputStream 是一个抽象概念;它有一百万种实现。 (不仅仅是“FileOutputStream 是一种实现”,而是“FileOutputStream,在 OpenJDK11 上,在 Windows 10 上,带有这个 servicepack,这个 CPU 和这么多系统内存,在这些情况下”)。

    您看到的原因是为了缓冲效率。发送 1 个字节的问题通常基本上没什么问题,但有时发送 1 个(或很少)字节会导致这种讨厌的情况:

    1. 你发送一个字节。
    2. 底层输出流并非设计用于缓冲该字节,它没有存储空间,因此它唯一能做的就是将其发送到实际的底层资源。假设 OutputStream 表示文件系统上的一个文件。
    3. 用于此的内核驱动程序的工作方式类似。 (大多数操作系统会在内部进行缓冲,但您可以在打开文件时要求操作系统不要这样做)。
    4. 因此,现在需要将一个字节写入磁盘。但是,它是 SSD,您不能对 SSD 执行此操作,您一次只能写入整个单元*。这就是 SSD 的工作原理:您只能写入整个块的价值。它们不是大盘子上按顺序排列的位。
    5. 因此,内核会读取整个单元格,更新您正在写入的一个字节,然后将整个单元格写回 SSD。
    6. 您的实际循环确实写入了,比如说,大约 50,000 字节,因此本应读取和写入单个 SSD 的东西,现在需要 50,000 次读取和 50,000 次写入,耗尽您的 SSD 单元寿命,并比所需时间长 50,000 倍。

    网络也会出现类似的问题(最终发送一个字节,包裹在 HTTP 标头中,包裹在 2 个 TCP/IP 数据包中,导致 .write(singleValue) 和许多其他此类系统的每个字节通过网络发送约 1000 个字节.

    那么为什么这些流不缓冲呢?

    因为在某些情况下,您实际上并不希望他们这样做;编写 I/O 时要考虑到特定的效率有很多理由。

    有没有办法只为我做点什么?

    啊,你很幸运,有! BufferedWriter 和朋友们(BufferedOutputStream 也存在)为您环绕底层流和缓冲区:

    var file = new FileOutputStream("/some/path");
    var wrapped = new BufferedOutputStream(file);
    file.write(1); // this is a bad idea
    wrapped.write(1); // this is fine
    

    在这里,包装后的写入不会导致任何事情发生,除了一些内存被推到周围。没有字节写入磁盘(缺点是如果有人绊倒电源线,它就会丢失)。只有在您关闭wrapped,或在包装时调用flush(),或向wrapped 写入足够数量的字节后,包装最终才会真正向底层流发送一大堆字节。 如果制作字节数组不方便,您应该使用它。为什么要重新发明轮子?

    但我想写入底层原始流

    好吧,如果字节数少于单个 TCP/IP 数据包可以容纳的字节数,或者不幸的大小,那么您使用的字节太少(想象一下 TCP/IP 数据包可以容纳 1000 个字节,而您发送 1001 和字节。这是一个完整的数据包,然后是一个只有 1 个字节的第二个数据包,只给你 50% 的效率。50% 仍然比 0.1% 的效率要好,在这个假设中,一次一个字节可以让你得到)。但是,如果你发送,比如说,5001 字节,那就是 5 个完整的数据包和一个令人遗憾的 1 字节数据包,效率为 83.35%。不幸的是,它没有接近 100,但也没有那么糟糕。这同样适用于磁盘(如果 SSD 单元保存 2048 字节,而您发送 65537 字节,它的效率仍然约为 96/7%)。

    如果对您自己的 java 进程的影响会导致出现问题,那么您使用的字节数过多:这会导致过多的垃圾收集,或者更糟糕的是,内存不足错误。

    那么“甜蜜点”在哪里?取决于一点点,但65536 很常见,不太可能“太低”。除非您同时运行数千个线程,否则它也不会太高。

    它通常是 2 的幂,主要是因为迷信,但它有一些意义:那些底层的缓冲区通常是 2 的幂(毕竟计算机是二进制的东西)。因此,如果单元格大小恰好是 2048,那么如果您发送 65536 个字节(这正是 32 个单元格的数据),那么您的效率是 100%。

    但是,您真正要避免的唯一事情是,如果您一次将一个字节写入打包(SSD、网络等)底层流,则会出现 0.1% 的效率。所以,没关系,只要超过2048左右,你就应该已经避免了厄运。

    *) 我过于简单化了;关键是单个字节的读取或写入可能会花费整个数据块的时间,并给出一些提示,说明为什么会这样,而不是对 SSD 技术进行完整的深入研究。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-18
      • 2012-12-15
      • 1970-01-01
      • 1970-01-01
      • 2011-06-21
      • 1970-01-01
      相关资源
      最近更新 更多