通过带有对象输入/输出流的 Socket 发送的对象的大小真的很重要吗?
刷新是否更有效每次单独调用 ObjectOutputStream#writeObject 而不是在一系列对象写入后刷新流? (例如:写入对象并刷新 4 次,或者写入 4 次然后只刷新一次?)
ObjectOutputStream 在内部工作?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这并不更好。事实上,从性能角度来看,情况可能更糟。每一次刷新都会强制操作系统级 TCP/IP 堆栈“立即”发送数据。如果最后只执行一次刷新,则应该节省系统调用和网络流量。
如果您还没有这样做,在
Socket
OutputStream
和ObjectOutputStream
之间插入一个BufferedOutputStream
将创建一个性能差异更大。这允许序列化数据在写入套接字流之前累积在内存中。这可能会节省许多系统调用,并且可以将性能提高数量级...具体取决于发送的实际对象。(四个
Object[5]
对象的表示大于一个Object[20]
对象,这会导致第一种情况下的性能下降。但是,这是顶多是微不足道的,与冲洗和缓冲问题相比微乎其微。)这是一个太笼统的问题,无法明智地回答。我建议您从 上的文档开始阅读序列化此页面。
It is not better. In fact it is probably worse, from a performance perspective. Each of those flushes will force the OS-level TCP/IP stack to send the data "right now". If you just do one flush at the end, you should save on system calls, and on network traffic.
If you haven't done this already, inserting a
BufferedOutputStream
between theSocket
OutputStream
and theObjectOutputStream
will make a much bigger difference to performance. This allows the serialized data to accumulate in memory before being written to the socket stream. This potentially save many system calls and could improve performance by orders of magnitude ... depending on the actual objects being sent.(The representation of four
Object[5]
objects is larger than oneObject[20]
object, and that results in a performance hit in the first case. However, this is marginal at most, and tiny compared with the flushing and buffering issues.)That is too general a question to answer sensibly. I suggest that you read up on serialization starting with the documents on this page.
不,这应该不重要,除非您有理由相信网络链接可能会中断,并且部分数据是有用的。否则,这听起来像是一种无缘无故地使代码变得更加复杂的方法。
No, it shouldn't matter, unless you have reason to believe the net link is likely to go down, and partial data is useful. Otherwise it just sounds like a way to make the code more complex for no reason.
如果您查看 ObjectOutputStream 的唯一一个公共构造函数,您会注意到它需要一个底层的
OutputStream
来进行实例化。刷新 ObjectStream 的时间和方式完全取决于您使用的流的类型。 (在考虑所有这些时,请记住,并非所有 OutputStream 扩展都保证尊重您的刷新请求 - 它完全独立于实现,正如 javadocs 的“契约”中所阐明的那样。)
但是我们当然可以推理甚至拉出代码看看实际做了什么。
IFF底层OutputStream必须利用设备的操作系统服务(例如磁盘或套接字情况下的网络接口 ) 那么flush()的行为完全依赖于操作系统。例如,您可以获取套接字的输出流,然后实例化 ObjectOutputStream 以将序列化对象写入网络。主机操作系统的 TCP/IP 实现负责。
什么更有效?
好吧,如果您的对象流包装 ByteArrayOutputStream,您可能正在查看一系列重新分配和 System.arrayCopy() 调用。我说的是潜在的,因为字节数组的实现使每个(内部)resize()操作的大小加倍,并且每次写入n个(小)对象并刷新不太可能导致n次重新分配。 (其中 n 被假定为一个相当小的数字)。
但如果您要包装网络流,则必须记住网络写入的成本非常昂贵。如果您的协议允许,将写入分块(以填充发送缓冲区)并只刷新一次,则更有意义。
If you look at the one and only public constructor of ObjectOutputStream, you note that it requires an underlying
OutputStream
for its instantiation.When and how you flush your ObjectStream is entirely dependent on the type of stream you are using. (And in considering all this, do keep in mind that not all extension of OutputStream are guaranteed to respect your request to flush -- it is entirely implementation independent, as it is spelled out in the 'contract' of the javadocs.)
But certainly we can reason about it and even pull up the code and see what is actually done.
IFF the underlying OutputStream must utilize the OS services for devices (such as the disk or the network interface in case of Sockets) then the behavior of flush() is entirely OS dependent. For example, you may grab the output stream of a socket and then instantiate an ObjectOutputStream to write serialized objects to the net. TCP/IP implementation of the host OS is in charge.
What is more efficient?
Well, if your object stream is wrapping a ByteArrayOutputStream, you are potentially looking at a series of reallocs and System.arrayCopy() calls. I say potentially, since the implementation of byte array doubles the size on each (internal) resize() op and it is very unlikely that writing n (small) objects and flushing each time will result in n reallocs. (Where n is assumed to be a reasonably small number).
But if you are wrapping a network stream, you must keep in mind that network writes are very expensive. It makes much more sense, if your protocol allows it, to chunk your writes (to fill the send buffer) and just flush once.