java - Tomcat Servlet性能: StringBuilder vs.直接写入

标签 java tomcat servlets networking

这是一篇针对 tomcat/网络专家的文章。我会对它进行基准测试/wireshark,但这要求相当高,也许有人立刻就知道答案。

比较这两种生成 servlet 输出的方法,从用户的角度来看哪一种是最快的:

  1. 直接写入 servlet 输出流:

    for( int i=0; i<10000; i++ ) { servletOutputStream.write(“a”); /* 一点点延迟 */ }

  2. 创建缓冲区并一轮写入

    for( int i=0; i<10000; i++ ) { stringbuffer.append(“a”); } servletOutputStream.write( stringBuffer.toString() )

我可以想象方法 1 的优点是响应可以快速开始发送内容,而方法 2 则稍后开始发送。

另一方面,方法 1 可能会生成更多/更小的 TCP 数据包,从而可能需要更长的时间才能完全传输?

问候

PS:请不要告诉我这是不成熟的优化。在当前的情况下,我有一个对象提供了 toString 和 write(Appendable a) 方法。我只需要选择在这里使用哪一个即可。此外,我发现从理论角度和 servlet 的一般设计来看这非常有趣。

编辑:感谢大家的回答。但看来我的问题不清楚或过于简化了我的例子。

我根本不担心不缓冲。我知道发送队列中至少有一处必须有缓冲。可能它在多个地方(Java、操作系统、硬件)。我认为我真正的问题是:这些缓冲区何时刷新?

为了更清楚地说明这一点,我们假设 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 

(顾名思义)是一个缓冲流。这意味着最好将字符直接写入流,而不是将它们组装在 StringBufferStringBuilder 中并写入结果。直接写入会避免至少一份字符的复制。

如果您的 ServletOutputStream 尚未缓冲,那么您可以将其包装在 BufferedOutputStream 中,您将得到相同的结果。


假设现在您正在谈论流。 (刷新StringBuffer没有任何意义。)

When is are these buffers flushed?

当它们已满时,当您在流上调用 flush 时,或者当流关闭时。

... and what would be the the best strategy of using it?

一般来说,写入数据,完成后关闭文件。不要明确地冲洗,除非有充分的理由这样做。如果您传递普通的 HTTP 响应,则很少有这种情况。 (刷新可能会导致网络堆栈通过发送更多网络数据包来传输相同数量的信息。这可能会影响整体网络吞吐量。)

就 servlet 框架而言,我记得 Servlet 规范规定,当请求/响应处理完成时,ServletOutputStream 将自动刷新并关闭。如果您没有包装 ServletOutputStream,您甚至不需要关闭该流。 (不过这并没有什么坏处。)

关于java - Tomcat Servlet性能: StringBuilder vs.直接写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32758501/

相关文章:

javascript - Java Servlet 更改后 Web 内容未更新

java - 使用 JPQL 和 BooleanExpression 进行分页

java - 您如何在对象类中实现枚举 - Java?

tomcat - 我如何找到 Tomcat 的 servlet-api.jar 的位置?

angularjs - 在本地 tomcat 上运行 AngularJS 编码的基本应用程序无法正常工作

java - 如何在servlet中获取本地文件

java - 使用 NuoDB 编写 servlet

java - 在 osgi maven 包中以编程方式更改 log4j 文件名不起作用

java - 无法找出文件中的句子数

java - Spring-boot - 如何加载资源/数据源?