21

I can write non-blocking I/O in Node.js very easily. It's what the entire library is set up for.

But any computation done is blocking. Any message passing over event emitters are blocking.

For example, emitting events are resolved immediately and are thus blocking:

var e = new process.EventEmitter;
e.on("foo", function() {
    console.log("event");
});
process.nextTick(function() {
    console.log("next tick");
});
setTimeout(function() {
    console.log("timeout");
}, 0);
e.emit("foo");

> event
> next tick
> timeout

Apart from wrapping calls in nextTick, how do I make code non-blocking?

I want to do as little computation per cycle of the event loop as possible, so that I can serve as many clients simultaneously as possible.

How do I write my code in a non-blocking fashion?

And when I have non-blocking code, how do I scale that across multiple processes?

One option is waiting for the WebWorker sub-process API to be finished.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Raynos
  • 166,823
  • 56
  • 351
  • 396
  • 3
    Firstly, 90% of your 'Question' is not actually a question, it's more of an issue with node's Event Library, this should be brought up either as a feature request or as a possible bug on github, as for your small question I would create a question dedicated to that subject rather then squeezing it in this one. – RobertPitt Apr 14 '11 at 22:09
  • 1
    @RobertPitt thank you for pointing out that the question was phrased poorly. i have adjusted it. I might also mention it on github. – Raynos Apr 14 '11 at 22:14
  • That's a little better, thankyou. – RobertPitt Apr 14 '11 at 22:21

2 Answers2

9

JavaScript is single-threaded. That means that regardless of events, timeouts, or delaying with nextTick, any computation done will block the whole process.

If you split your processing in steps using process.nextTick, like it's done with setTimeout(fn, 0) on the client-side to avoid blocking the UI, you could spread your workload over a longer time span, giving some room for other functions to run.

But that's a very innefective solution - the total amount of work is the same, distributed among all cycles (making each request a little slower). In practice, any kind of computation that is expected to take more than a few milliseconds should be offloaded to a different process. To maximize concurrency you should always return to the event loop as quickly as possible.

child_process.fork() was added to v0.5 a few days ago. It simplifies child process creation and communication - not quite the web workers API, but close, see the URL https://github.com/joyent/node/blob/master/doc/api/child_process.markdown.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ricardo Tomasi
  • 34,573
  • 2
  • 55
  • 66
  • That's exactly what I showed in my snippet. The event handling is blocking. My question is how do I do non blocking message passing to optimise concurrency? I guess calling process.nextTick is the best way. – Raynos Apr 14 '11 at 23:35
  • @RicardoTomasi using `process.nextTick` is non-blocking as it allows other task to get CPU time. It's basically time splicing one CPU to make it multi threaded. – Raynos Apr 19 '11 at 19:22
  • 7
    Javascript is still single threaded, and your functions will "block" regardless of their placing. The _other tasks_ will also block, you'll be just switching their order. **If** you split your processing in steps, like it's done client-side to avoid blocking the UI, you can spread the same amount of work over a longer time - then you might get a little better concurrency, but in exchange for longer response times. This is not what node.js is about. The benefits of non-blocking code come from not sitting idle waiting for responses, not from avoiding all computations. – Ricardo Tomasi Apr 21 '11 at 06:16
  • 1
    @RicardoTomasi that final comment really sums up my misconceptions. If you can edit the answer to explain my misconception I'll accept it – Raynos May 12 '11 at 00:49
  • @Raynos edited. also added a mention to the new `.fork()` API, you should take a look at it. – Ricardo Tomasi May 19 '11 at 00:11
1

There's no real multi-threading in JavaScript and that's what you need to make the call non-blocking. The only thing I can think of are web-workers: https://developer.mozilla.org/en/Using_web_workers

Cristian Vrabie
  • 3,972
  • 5
  • 30
  • 49
  • 2
    Then again, I haven't programmed in JS for several years so I might be wrong. – Cristian Vrabie Apr 14 '11 at 22:11
  • callbacks on `process.nextTick` are non-blocking. You can use an event loop to write non blocking code but the event emitters do not make use of the event loop. I don't know how to make use of the event loop. – Raynos Apr 14 '11 at 22:15