Char[] to Byte[] for output optimize in web (jav

2019-08-07 11:29发布

I just find in an experence share presentation from infoq. It claims that if you convert the String to byte[] in servlet, it will increase the QPS (Queries per Second?). The code example shows the comparison:

Before

private static String content = “…94k…”;
protected doGet(…){
response.getWrite().print(content);
}

After

private static String content = “…94k…”;
Private static byte[] bytes = content.getBytes();
protected doGet(…){
response.getOutputStream().write(bytes);
}

Result before

  • page size(K)94
  • max QPS 1800

Result after

  • page size(K)94
  • max QPS 3500

Can anyone explain why it was optimized? I trust it to be true.

UPDATE

In case I cause any misleading. I need explain that the original presentation only uses this as an example. They actually refactor the velocity engine by this way. BUt this source code is a bit long.

Actually in the presentation didn't imply how they do it in detail. But I found some lead.

In ASTText.java, they cached the byte[] ctext instead of char[] ctext , which boosts the performance a lot~!

Just like the way above. It makes a lot of sense,right?

(BUT definitely they should also refactor the Node interface. Writer cannot write byte[]. Which means using OutputStream instead!)

As Perception adviced actually a Write finally delegate to a StreamEncoder. And StreamEncoder write will first change char[] into byte[]. And then delegate it to the OutputSteam to do the real write. You can easily refer to the source code and prove it. Considering render method will be called each time for showing the page, the saving of cost will be considerable.

StreamEncoder.class

 public class ASTText extends SimpleNode {
            private char[] ctext;
        /**
         * @param id
         */
        public ASTText(int id) {
            super (id);
        }

        /**
         * @param p
         * @param id
         */
        public ASTText(Parser p, int id) {
            super (p, id);
        }

        /**
         * @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
         */
        public Object jjtAccept(ParserVisitor visitor, Object data) {
            return visitor.visit(this , data);
        }

    /**
     * @see org.apache.velocity.runtime.parser.node.SimpleNode#init(org.apache.velocity.context.InternalContextAdapter, java.lang.Object)
     */
    public Object init(InternalContextAdapter context, Object data)
            throws TemplateInitException {
        Token t = getFirstToken();

        String text = NodeUtils.tokenLiteral(t);

        ctext = text.toCharArray();

        return data;
    }

    /**
     * @see org.apache.velocity.runtime.parser.node.SimpleNode#render(org.apache.velocity.context.InternalContextAdapter, java.io.Writer)
     */
    public boolean render(InternalContextAdapter context, Writer writer)
            throws IOException {
        if (context.getAllowRendering()) {
            writer.write(ctext);
        }
        return true;
    }
}

1条回答
Melony?
2楼-- · 2019-08-07 12:16

Apart from the fact that you aren't calling the same output methods, in your second example you avoid the overhead of converting the String to bytes before writing it to the output stream. These scenarios are not very realistic though, the dynamic nature of web applications precludes pre-converting all your data models into byte streams. And, there are no serious architectures out there now where you will be writing directly to the HTTP output stream like this.

查看更多
登录 后发表回答