8

I have a heavy data processing operation that I need to get done per 10-12 simulatenous request. I have read that for higher level of concurrency Node.js is a good platform and it achieves it by having an non blocking event loop.

What I know is that for having things like querying a database, I can spawn off an event to a separate process (like mongod, mysqld) and then have a callback which will handle the result from that process. Fair enough.

But what if I want to have a heavy piece of computation to be done within a callback. Won't it block other request until the code in that callback is executed completely. For example I want to process an high resolution image and code I have is in Javascript itself (no separate process to do image processing).

The way I think of implementing is like

get_image_from_db(image_id, callback(imageBitMap) {
    heavy_operation(imageBitMap); // Can take 5 seconds.
});

Will that heavy_operation stop node from taking in any request for those 5 seconds. Or am I thinking the wrong way to do such task. Please guide, I am JS newbie.

UPDATE

Or can it be like I could process partial image and make the event loop go back to take in other callbacks and return to processing that partial image. (something like prioritising events).

Sushant Gupta
  • 8,980
  • 5
  • 43
  • 48

3 Answers3

5

Yes it will block it, as the callback functions are executed in the main loop. It is only the asynchronously called functions which do not block the loop. It is my understanding that if you want the image processing to execute asynchronously, you will have to use a separate processes to do it.

Note that you can write your own asynchronous process to handle it. To start you could read the answers to How to write asynchronous functions for Node.js.

UPDATE

how do i create a non-blocking asynchronous function in node.js? may also be worth reading. This question is actually referenced in the other one I linked, but I thought I'd include it here to for simplicity.

Community
  • 1
  • 1
Nick Mitchinson
  • 5,452
  • 1
  • 25
  • 31
  • But if I have separate process for that heavy operation and if I have say 15 requests coming in. Won't it create 15 processes. That would be real costly. Can't I like create threads in node. Thanks for your answer by the way. I will accept it once I get my doubts cleared :) – Sushant Gupta Mar 10 '13 at 00:51
  • 2
    Yes it will create 15 processes, and as far as I know you cannot create threads in Node. It has one thread, which is your main event loop. Another option is to write a separate Node worker application which does the image processing for tasks passes to it through a messaging queue (RabbitMQ or something). This however would only process the images syncronously (one at a time). If you want them processed at the same time, you'll have to create seperate processes. – Nick Mitchinson Mar 10 '13 at 00:59
  • I think I got the catch now. Thanks mate for your help and time. – Sushant Gupta Mar 10 '13 at 01:03
4

Unfortunately, I don't yet have enough reputation points to comment on Nick's answer, but have you looked into Node's cluster API? It's currently still experimental, but it would allow you to spawn multiple threads.

John Henry
  • 2,419
  • 2
  • 20
  • 22
4

When a heavy piece of computation is done in the callback, the event loop would be blocked until the computation is done. That means the callback will block the event loop for the 5 seconds.

My solution

It's possible to use a generator function to yield back control to the event loop. I will use a while loop that will run for 3 seconds to act as a long running callback.

Without a Generator function

let start = Date.now();

setInterval(() => console.log('resumed'), 500);
function loop() {
    while ((Date.now() - start) < 3000) { //while the difference between Date.now() and start is less than 3 seconds
        console.log('blocked')
    }
}

loop();

The output would be:

// blocked
// blocked
//
//  ... would not return to the event loop while the loop is running
//
// blocked
//...when the loop is over then the setInterval kicks in
// resumed
// resumed

With a Generator function

let gen;
let start = Date.now();

setInterval(() => console.log('resumed'), 500);

function *loop() {
    while ((Date.now() - start) < 3000) { //while the difference between Date.now() and start is less than 3 seconds
        console.log(yield output())
    }
}

function output() {
    setTimeout(() => gen.next('blocked'), 500)
}

gen = loop();
gen.next();

The output is:

// resumed
// blocked
//...returns control back to the event loop while though the loop is still running
// resumed
// blocked
//...end of the loop
// resumed
// resumed
// resumed

Using javascript generators can help run heavy computational functions that would yield back control to the event loop while it's still computing.

To know more about the event loop visit https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/function*

https://davidwalsh.name/es6-generators

Kayslay
  • 111
  • 5