title: node.js performance with zeromq vs. Python vs. Java
body: <p>I've written a simple echo request/reply test for zeromq using node.js, Python, and Java. The code runs a loop of 100K requests. The platform is a 5yo MacBook Pro with 2 cores and 3G of RAM running Snow Leopard.</p>
  
  <p>node.js is consistently an order of magnitude slower than the other two platforms.</p>
  
  <p>Java:
  <code>real    0m18.823s
  user    0m2.735s
  sys     0m6.042s</code></p>
  
  <p>Python:
  <code>real    0m18.600s
  user    0m2.656s
  sys     0m5.857s</code></p>
  
  <p>node.js:
  <code>real    3m19.034s
  user    2m43.460s
  sys     0m24.668s</code></p>
  
  <p>Interestingly, with Python and Java the client and server processes both use about half of a CPU. The client for node.js uses just about a full CPU and the server uses about 30% of a CPU. The client process also has an enormous number of page faults leading me to believe this is a memory issue. Also, at 10K requests node is only 3 times slower; it definitely slows down more the longer it runs.</p>
  
  <p>Here's the client code (note that the process.exit() line doesn't work, either, which is why I included an internal timer in addition to using the time command):</p>
  
  <pre><code>var zeromq = require("zeromq");
  
  var counter = 0;
  var startTime = new Date();
  
  var maxnum = 10000;
  
  var socket = zeromq.createSocket('req');
  
  socket.connect("tcp://127.0.0.1:5502");
  console.log("Connected to port 5502.");
  
  function moo()
  {
      process.nextTick(function(){
          socket.send('Hello');
          if (counter &lt; maxnum)
          {
              moo();
          }
      });
  }
  
  moo();
  
  socket.on('message',
            function(data)
            {
                if (counter % 1000 == 0)
                {
                    console.log(data.toString('utf8'), counter);
                }
  
                if (counter &gt;= maxnum)
                {
                    var endTime = new Date();
                    console.log("Time: ", startTime, endTime);
                    console.log("ms  : ", endTime - startTime);
                    process.exit(0);
                }
  
                //console.log("Received: " + data);
                counter += 1;
  
            }
  );
  
  socket.on('error', function(error) {
    console.log("Error: "+error);
  });
  </code></pre>
  
  <p>Server code:</p>
  
  <pre><code>var zeromq = require("zeromq");
  
  var socket = zeromq.createSocket('rep');
  
  socket.bind("tcp://127.0.0.1:5502",
              function(err)
              {
                  if (err) throw err;
                  console.log("Bound to port 5502.");
  
                  socket.on('message', function(envelope, blank, data)
                            {
                                socket.send(envelope.toString('utf8') + " Blancmange!");
                            });
  
                  socket.on('error', function(err) {
                      console.log("Error: "+err);
                  });
              }
  );
  </code></pre>
  
  <p>For comparison, the Python client and server code:</p>
  
  <pre><code>import zmq
  
  context = zmq.Context()
  socket = context.socket(zmq.REQ)
  socket.connect("tcp://127.0.0.1:5502")
  
  for counter in range(0, 100001):
      socket.send("Hello")
      message = socket.recv()
  
      if counter % 1000 == 0:
          print message, counter
  
  
  
  import zmq
  
  context = zmq.Context()
  socket = context.socket(zmq.REP)
  
  socket.bind("tcp://127.0.0.1:5502")
  print "Bound to port 5502."
  
  while True:
      message = socket.recv()
      socket.send(message + " Blancmange!")
  </code></pre>
  
  <p>And the Java client and server code:</p>
  
  <pre><code>package com.moo.test;
  
  import org.zeromq.ZMQ;
  import org.zeromq.ZMQ.Context;
  import org.zeromq.ZMQ.Socket;
  
  public class TestClient
  {
      public static void main (String[] args)
      {
          Context context = ZMQ.context(1);
  
          Socket requester = context.socket(ZMQ.REQ);
          requester.connect("tcp://127.0.0.1:5502");
  
          System.out.println("Connected to port 5502.");
  
          for (int counter = 0; counter &lt; 100001; counter++)
          {
              if (!requester.send("Hello".getBytes(), 0))
              {
                  throw new RuntimeException("Error on send.");
              }
  
              byte[] reply = requester.recv(0);
              if (reply == null)
              {
                  throw new RuntimeException("Error on receive.");
              }
  
              if (counter % 1000 == 0)
              {
                  String replyValue = new String(reply);
                  System.out.println((new String(reply)) + " " + counter);
              }
          }
  
          requester.close();
          context.term();
      }
  }
  
  package com.moo.test;
  
  import org.zeromq.ZMQ;
  import org.zeromq.ZMQ.Context;
  import org.zeromq.ZMQ.Socket;
  
  public class TestServer
  {
      public static void main (String[] args) {
          Context context = ZMQ.context(1);
  
          Socket socket  = context.socket(ZMQ.REP);
          socket.bind("tcp://127.0.0.1:5502");
  
          System.out.println("Bound to port 5502.");
  
          while (!Thread.currentThread().isInterrupted())
          {
              byte[] request = socket.recv(0);
              if (request == null)
              {
                  throw new RuntimeException("Error on receive.");
              }
  
              if (!socket.send(" Blancmange!".getBytes(), 0))
              {
                  throw new RuntimeException("Error on send.");
              }
          }
  
          socket.close();
          context.term();
      }
  }
  </code></pre>
  
  <p>I would like to like node, but with the vast difference in code size, simplicity, and performance, I'd have a hard time convincing myself at this point.</p>
  
  <p>So, has anyone seen behavior like this before, or did I do something asinine in the code?</p>