java - 字节数组输出流
问题描述
可能是一个愚蠢的问题,但字节数组发送的理想长度是outputstream
多少?我在网上找不到有关此的任何信息。
我发现了很多将它们的数组大小设置为 2^X 或类似的示例。但这样做的目的是什么?
解决方案
没有最佳尺寸。OutputStream 是一个抽象概念;它有一百万种实现。(不仅仅是“FileOutputStream 是一种实现”,而是“FileOutputStream,在 OpenJDK11 上,在 Windows 10 上,带有这个 servicepack,这个 CPU 和这么多系统内存,在这些情况下”)。
您看到的原因是为了缓冲效率。发送 1 个字节的问题通常基本上没什么问题,但有时,发送 1 个(或很少)字节会导致这种讨厌的情况:
- 你发送一个字节。
- 底层的输出流不是为了缓冲那个字节而设计的,它没有存储空间,所以它唯一能做的就是将它发送到实际的底层资源。假设 OutputStream 代表文件系统上的一个文件。
- 用于此的内核驱动程序的工作方式类似。(大多数操作系统会在内部进行缓冲,但您可以在打开文件时要求操作系统不要这样做)。
- 因此,现在需要将一个字节写入磁盘。但是,它是 SSD,您不能对 SSD 执行此操作,您一次只能写入整个单元*。这就是 SSD 的工作原理:您只能写入整个块的价值。它们不是大盘子上按顺序排列的位。
- 因此,内核读取整个单元格,更新您正在写入的一个字节,并将整个单元格写回 SSD。
- 例如,您的实际循环确实写入了大约 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 技术进行完整的深入研究。
推荐阅读
- html - 为什么当我将鼠标悬停在图标栏上时,悬停不起作用?
- swift - SwiftUI 菜单从上到下的顺序因上下文而异?
- spring-boot - 如何使用 Spring Boot + Spring Security + KeyCloak 验证每个请求?
- docker - 如何在 ubuntu 上使用 docker-compose 应用程序路由流量?
- python - Pandas groupby,如何编辑结果
- android - 如何使用recycleview创建多个按钮
- android - 我可以让 iOS/Android 应用程序“响铃”以强制用户响应推送通知吗?
- python - 有人可以用 Python 解释“diff = \ floor(a - b))”吗?
- html - 我怎样才能解决这些错误?
- python - 在 R 或 Python 中打开 Stata 16 .dta?