title: Netty vs Tornado by performance?
body: <p>I try to stress test <strong>WebSocketServer</strong> under Netty and compare it with hello demo in <strong>Tornado</strong>.</p>
  
  <p>Both receive and response a "hello world html" and I stress test by <strong>Siege</strong>.
  They are run under exactly the same environment.</p>
  
  <p>We expect native java should be faster than Tornado/Python. However, the result is:
  Tornado/Python is about <strong>2X faster than</strong> Netty in term of no. of request handled per second.</p>
  
  <p>Can anyone explain why native Java is slower?
  Is the test correct?</p>
  
  <p>Thanks</p>
  
  <p><strong>JAVA</strong>:  Transaction rate:             657.89 trans/sec
  <strong>Python</strong>: Transaction rate:            1435.41 trans/sec</p>
  
  <h2>JAVA WebSocketServer</h2>
  
  <pre><code>public class WebSocketServer {
  
  private final int port;
  
  public WebSocketServer(int port) {
      this.port = port;
  }
  
  public void run() {
      // Configure the server.
      ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(
              Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
  
      // Set up the event pipeline factory.
      bootstrap.setPipelineFactory(new WebSocketServerPipelineFactory());
  
      // Bind and start to accept incoming connections.
      bootstrap.bind(new InetSocketAddress(port));
  
      System.out.println("Web socket server started at port " + port + '.');
      System.out.println("Open your browser and navigate to http://localhost:" + port + '/');
  }
  
  public static void main(String[] args) {
      int port;
      if (args.length &gt; 0) {
          port = Integer.parseInt(args[0]);
      } else {
          port = 8888;
      }
      new WebSocketServer(port).run();
  }
  </code></pre>
  
  <p>}</p>
  
  <h2>JAVA Message Handler</h2>
  
  <pre><code>@Override
  public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
      Object msg = e.getMessage();
      if (msg instanceof HttpRequest) {
          handleHttpRequest(ctx, (HttpRequest) msg);
      } else if (msg instanceof WebSocketFrame) {
          handleWebSocketFrame(ctx, (WebSocketFrame) msg);
      }
  }
  private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
      HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK);
      // ChannelBuffer content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req));
      ChannelBuffer content = ChannelBuffers.copiedBuffer( "&lt;html&gt;&lt;body&gt;hello!&lt;/body&gt;&lt;/html&gt;", CharsetUtil.US_ASCII);
  
  
      res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8");
      setContentLength(res, content.readableBytes());
  
      res.setContent(content);
      sendHttpResponse(ctx, req, res);
      return;
  
  }
  
  private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
  
      // Check for closing frame
      if (frame instanceof CloseWebSocketFrame) {
          handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame);
          return;
      } else if (frame instanceof PingWebSocketFrame) {
          ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData()));
          return;
      } else if (!(frame instanceof TextWebSocketFrame)) {
          throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass()
                  .getName()));
      }
  
      // Send the uppercase string back.
      String request = ((TextWebSocketFrame) frame).getText();
      if (logger.isDebugEnabled()) {
          logger.debug(String.format("Channel %s received %s", ctx.getChannel().getId(), request));
      }
      ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase()));
  }
  
  private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
      // Generate an error page if response status code is not OK (200).
      if (res.getStatus().getCode() != 200) {
          res.setContent(ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8));
          setContentLength(res, res.getContent().readableBytes());
      }
  
      // Send the response and close the connection if necessary.
      ChannelFuture f = ctx.getChannel().write(res);
      if (!isKeepAlive(req) || res.getStatus().getCode() != 200) {
          f.addListener(ChannelFutureListener.CLOSE);
      }
  }
  </code></pre>
  
  <h2>Python under Tornado</h2>
  
  <pre><code>define("port", default=8888, help="run on the given port", type=int)
  
  
  class MainHandler(tornado.web.RequestHandler):
  def get(self):
      self.write("Hello, world")
  
  
  def main():
      tornado.options.parse_command_line()
      application = tornado.web.Application([
          (r"/", MainHandler),
      ])
      http_server = tornado.httpserver.HTTPServer(application)
      http_server.listen(options.port)
      tornado.ioloop.IOLoop.instance().start()
  
  
  if __name__ == "__main__":
      main()
  </code></pre>