这是供Tomcat /网络专家使用的工具。我会对其进行基准测试/ Wireshark,但这要求很高,也许有人会立即知道答案。
比较这两种生成servlet输出的方法,从用户的角度来看,这是最快的方法:
直接写入servlet输出流:
for(int i = 0; i servletOutputStream.write(“ a”);
/ *有点延迟* /
}
创建一个缓冲区并一圈写入
for(int i = 0; i stringbuffer.append(“ a”);
}
servletOutputStream.write(stringBuffer.toString())
我可以想象方法1的优点是响应可以快速开始发送内容,而方法2中的发送则稍后开始。
另一方面,方法1可以生成更多/较小的TCP数据包,进而需要更长的时间才能完全传输?
问候
PS:请不要告诉我这是过早的优化。在目前的情况下,我有一个同时提供toString
和write(Appendable a)
方法的对象。我只需要选择在这里使用哪个。另外,从理论的角度以及关于Servlet的一般设计,我发现这非常有趣。
编辑:谢谢大家的答案。但是看来我不清楚我的问题还是简化了我的例子。
我完全不担心不缓冲。我知道发送队列中至少必须在一个地方缓冲。可能在多个地方(Java,OS,硬件)。我认为我真正的问题是:这些缓冲区何时刷新?
因此,更清楚地说,假设我们的MTU为1000,并且连续数据包的发送是由硬件的缓冲区空中断触发的。然后,在第一种情况下,它可能看起来像:
. packet( "a" ) //triggered by the first write( "a" ),
. packet( "aaaaaaa" ) // triggered by buffer-empty, sending the amount of "a"s which have been written in the meantime
. packet( "aaaa" ) // and so on
. packet( "aaaaaaaaaaa" )
...x1000 // or so in this example
对于第二种情况,发送开始时所有10000字节已经可用,因此结果将是:
. packet( "aaaa....a(x1000)" )
. packet( "aaaa....a(x1000)" )
...x10
即使对于较小的数据大小(小于MTU,可以说100个“ a”),创建输出的速度也要比发送时间快,结果可能看起来像:
. packet( "a" ) // first write
. packet( "aaaa...a(x99) ) // all remaining data available when buffer-empty interrupt.
当然,如果缓冲区的工作方式不同,那么所有这些都将是安静的。例如。如果他们等待更多的数据发送或等待刷新发送任何东西...(但是这反过来也会在某些方面减慢发送速度)
所以这就是我所不知道的:tomcat中的这种缓冲到底是如何工作的,使用它的最佳策略是什么?
(而且我并不担心或期望获得更大的速度提升。我只是想知道事情的运行方式。)
最佳答案
我希望ServletOutputStream
实际上是
org.apache.tomcat.core.BufferedServletOutputStream
(顾名思义)这是一个缓冲的流。这将意味着最好直接将字符写入流中,而不是将它们组合到
StringBuffer
或StringBuilder
中并写入结果。直接书写将避免字符的至少一个副本。如果事实证明您的
ServletOutputStream
尚未被缓冲,则可以将其包装在BufferedOutputStream
中,您将获得相同的结果。假设现在您正在谈论流。 (刷新
StringBuffer
没有任何意义。)这些缓冲区什么时候刷新?
当它们已满时,当您在流上调用
flush
或关闭流时。...而使用它的最佳策略是什么?
通常,写入数据,完成后关闭文件。除非有充分的理由,否则不要显式刷新。如果要传递普通的HTTP响应,则很少。 (刷新可能会导致网络堆栈通过发送更多网络数据包来传输相同数量的信息。这可能会影响整体网络吞吐量。)
对于Servlet框架,我记得Servlet规范说
ServletOutputStream
将在请求/响应处理完成后自动刷新并关闭。只要您没有包装ServletOutputStream
,您甚至都不需要关闭流。 (但没有害处。)