这个问题可能很愚蠢,但是通过outputstream发送的字节数组的理想长度是多少?我在网上找不到任何关于这个的东西。
我发现了很多将数组大小设置为2^X或类似值的示例。但这样做的目的是什么?
发布于 2020-11-24 19:09:01
没有最佳大小。OutputStream是一个抽象的概念;它有一百万个实现。(不仅仅是“FileOutputStream是一种实现”,还有“FileOutputStream,在OpenJDK11上,在Windows10上,在这种情况下,有这个服务包,有这个中央处理器和这么多的系统内存”)。
您看到的原因是为了提高缓冲区效率。发送1个字节的问题通常不会有什么问题,但有时发送1(或很少)个字节会导致这种糟糕的情况:
类似的问题也出现在网络上(最终发送一个包含在HTTP头中的单个字节,再包含在两个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在这里,包装的写入不会导致任何事情发生,除了一些内存被推来推去。不会将字节写入磁盘(缺点是,如果有人被powercable绊倒,它就会丢失)。只有在您关闭wrapped,或者在wrapped上调用flush(),或者将足够的字节写入wrapped之后,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技术上做一个完整的深入研究。
https://stackoverflow.com/questions/64984809
复制相似问题