Warning: mysql_real_escape_string(): No such file or directory in /home/jostylr/mythiclogos.com/blog/wp-content/plugins/statsurfer/append.php on line 285

Warning: mysql_real_escape_string(): A link to the server could not be established in /home/jostylr/mythiclogos.com/blog/wp-content/plugins/statsurfer/append.php on line 285

Warning: mysql_real_escape_string(): No such file or directory in /home/jostylr/mythiclogos.com/blog/wp-content/plugins/statsurfer/append.php on line 285

Warning: mysql_real_escape_string(): A link to the server could not be established in /home/jostylr/mythiclogos.com/blog/wp-content/plugins/statsurfer/append.php on line 285

Warning: mysql_real_escape_string(): No such file or directory in /home/jostylr/mythiclogos.com/blog/wp-content/plugins/statsurfer/append.php on line 285

Warning: mysql_real_escape_string(): A link to the server could not be established in /home/jostylr/mythiclogos.com/blog/wp-content/plugins/statsurfer/append.php on line 285

Warning: mysql_real_escape_string(): No such file or directory in /home/jostylr/mythiclogos.com/blog/wp-content/plugins/statsurfer/append.php on line 285

Warning: mysql_real_escape_string(): A link to the server could not be established in /home/jostylr/mythiclogos.com/blog/wp-content/plugins/statsurfer/append.php on line 285

Warning: mysql_real_escape_string(): No such file or directory in /home/jostylr/mythiclogos.com/blog/wp-content/plugins/statsurfer/append.php on line 285

Warning: mysql_real_escape_string(): A link to the server could not be established in /home/jostylr/mythiclogos.com/blog/wp-content/plugins/statsurfer/append.php on line 285

Warning: mysql_real_escape_string(): No such file or directory in /home/jostylr/mythiclogos.com/blog/wp-content/plugins/statsurfer/append.php on line 285

Warning: mysql_real_escape_string(): A link to the server could not be established in /home/jostylr/mythiclogos.com/blog/wp-content/plugins/statsurfer/append.php on line 285
On Event Loops in node.js | Mythic Logos
Skip to content

On Event Loops in node.js

The wonderful environment of node.js uses an event loop rather than threading to deal with multiple incoming requests and more. Threading is tricky, or so I have been told. Event loops are less tricky, or so I have been told. Why?

I think the key reason is that threads are running at their own pace, separately. In event loops, until the loop loops, it is a single execution of logic. The idea is that there is a queue that takes in requests to act. Each time the current logic ends its execution, the queue is checked and the next action is taken, if any.

To demonstrate this, consider the simple node.js server, saved in server.js:

//server.js
/*globals require, console, process*/
var http = require('http');
var server = http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
});
server.listen(1337, "127.0.0.1");
server.on('close', function () {
  console.log('server closed');
});
console.log('Server running at http://127.0.0.1:1337/');

// on exit, let us know.
process.on('SIGINT', function () {
  console.log('server told to shut down');
  server.close();
});

This server should work by running node server. You should be able to send an interrupt with ctrl-c, at least on a Mac, initiating the close down procedures. Without the process.on, a ctrl-c kills the server immediately.

Next we add a while loop:

//noserver.js
/*globals require, console, process*/
var http = require('http');
var server = http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
});
server.listen(1337, "127.0.0.1");
server.on('close', function () {
  console.log('server closed');
});
console.log('Server running at http://127.0.0.1:1337/');

var count = 0;
while (1) {
  if (count % 1000000 === 0) {
    console.log(count / 1000000 );
  }
  count += 1;
}

Running this will produce a non-functioning sever. Why? Because the while loop never cedes control. The event loop is never accessed. To make sure you can kill it with ctrl-c, we remove the process.on block first.1

To be explicit about loop access, we need to use process.nextTick():

//servertick.js
/*globals require, console, process*/
var http = require('http');
http.createServer(function (req, res) {
 res.writeHead(200, {'Content-Type': 'text/plain'});
 res.end('Hello World\n');
}).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/'); 

var count = 0;
process.nextTick(function self () {
  if (count % 1000000 === 0) {
    console.log(count / 1000000 );
  }
  count += 1;
 process.nextTick(self);
});

Notice how there is no evident loop. The loop is the event loop itself. Every time the anonymous function self runs, it queues itself for the next loop. The function .nextTick is a queueing agent. As far as I know, there is no way to cede direct control to the event loop. All one can do is do an explicit queue action and be done with the executing logic for the moment.

An analogue to .nextTick in the browser is setTimeout(fn, 0) which is what browserify does. But the docs in ndoe.js claim that nextTick is much more efficient than that and, thus, actually different. Let’s test this by running the following code:

/*globals require, console, process*/

var times = 10e6;
var count = 0;

var start = (new Date()).getTime();

while (count < times) {
  count += 1;
}

var diff = (new Date()).getTime() - start;

console.log("while diff: "+diff+" count: "+count);

start = (new Date()).getTime();
count = 0;

process.nextTick(function self () {
  if (count  < times ) {
    count += 1;
    process.nextTick(self);
  } else {
    diff = (new Date()).getTime() - start;
    console.log("nextTick diff: "+diff+" count: "+count);
    start = (new Date()).getTime();
    count = 0;
    setTimeout(function setself () {
      if (count  < times ) {
        count += 1;
        setTimeout(setself, 0);
      } else {
        diff = (new Date()).getTime() - start;
        console.log("setTimeout diff: "+diff+" count: "+count);
        start = (new Date()).getTime();
        count = 0; 
        process.nextTick(function lesstick () {
          var i;
          for (i = 0; i < 1e6; i += 1) {
            count += 1; 
          }
          if (count  < times ) {
            process.nextTick(lesstick);
          } else {
            diff = (new Date()).getTime() - start;
            console.log("delayed nextTick diff: "+diff+" count: "+count);
          }
        });
      }
    }, 0);

  }
});

This is not written particularly well. A better style would be to define the functions separately and then do the callbacks. Or you can use events such as with eventingfunctions. But as you can see we first do a while loop. This is fast. Then we use nextTick callbacks. And we wait. Our third trial is setTimeout. We read a book. We come back and see the fourth trial uses nextTick, but does a million computations each time before releasing. This is fairly fast and will allow other stuff to happen. The results I obtained are2:

while diff: 34 count: 10000000
nextTick diff: 13840 count: 10000000
setTimeout diff: 109973 count: 10000000
delayed nextTick diff: 62 count: 10000000

As one can see, accessing the event loop is a costly procedure, but it is much better to use nextTick than setTimeout. For long running computations, a separate process is, of course, preferred. But at the least, use the trick in delayed NextTick.

The code can be found at github.com/jostylr


  1. I find ctrl-z, jobs -l, kill -s KILL # where # is the process number, works wonders.

  2. in milliseconds

{ 1 } Trackback

  1. Events in the Event Loop | Mythic Logos | January 14, 2012 at 4:58 pm | Permalink

    […] other day I wrote about the event loop in node.js. In particular, there is a nice trick of ceding control to the event loop using […]

Post a Comment

Your email is never published nor shared. Required fields are marked *