0

In the javascript program below (Euler problem 5) I am practicing writing asynchronous / non blocking function. The program is trying to find the smallest number evenly divisible by numbers 1-10. 2520 is the first smallest and that is where the program should stop.

I set up the program so that if the functions run together, then the second checkNum should be done first and print the second one first, then the first one, but that is not happening?

How can I get the function to run at the same time, instead of one after another? I am expecting the callback from the second checkNum function I call to be called first (since it starts closer to the answer), then the first, but that is not what happens. Thanks so much!

var divides = function(a, b) {
  return b % a == 0;
 };

function checkNum(counter, callback) {
   var noRemainder = 0;
   var forward = true;
    while (forward)
    {
    for (var i = 1; i <= 10; i++) {
         if (divides(i, counter))
          { noRemainder++; }
     }

    if (noRemainder == 10) {
       console.log(counter);
       forward = false;
       callback(counter);
    } else {
      console.log(noRemainder);
      noRemainder = 0;
      counter++;
      console.log(counter);
    }
  }
}

checkNum(1, function(counter) {
             setTimeout(function(){
                        console.log("The counter is: " + counter)},3000) 
              }
);

checkNum(2500, function(counter) {
               setTimeout(function(){
                          console.log("The counter2 is: " + counter) },3000)       

                }
);
1
  • 1
    I think you're confused between asynchronous and multithreaded/concurrent processing. I think what you want is to run these simultaneously and return asynchronously, not just asynchronously. Commented Oct 2, 2013 at 1:32

3 Answers 3

2

Because checkNum is a purely CPU-bound function – that is, the only thing it does is perform computation in a tight loop – there is no reason to make it asynchronous. The function is by definition synchronous; control does not return to the caller until computations complete. Consider the following async style:

checkNum(n, function(err, result) {
    console.log(result);
});
console.log('Next line');

...and synchronous style:

console.log( checkNum(n) );
console.log('Next line');

In both cases, the result of checkNum will be printed before "Next line". Even in the async style, control is not returned until after checkNum invokes its callback and the callback completes. (Compare this to truly asynchronous functions where "Next line" would get printed before the callback gets a result.)

The real magic of node comes from the fact that most expensive operations (like I/O) are performed on a separate thread by native code, and when they're done, they invoke a JavaScript callback on the main thread. As a result, very little time is spent executing JavaScript, so your application performs exceptionally well.

However, if you find yourself writing expensive loops and calculations like this in JavaScript, you have to remember that you'll be blocking everything for the amount of time your function runs. Things happening on other threads will queue up and your application code will not have a chance to do anything until the expensive function returns.

There are several ways to work around this limitation, in order of performance:

  • Break the calculations up into chunks and use nextTick to start the processing on each chunk. This allows any queued events to process between chunks.
  • Move your calculation function into a separate file, and start up a new process to actually do the calculation. This leaves your main app free to run normally while it waits for a result. You'll want to use fork to do this since it comes with built-in IPC. Here's an example fibonacci calculator. Keep in mind this does come with overhead: it takes ~30ms and at least 10 MB of RAM to start a new node process.
  • Actually run your JavaScript code on a separate thread. Note that code will run isolated from the rest of your app; your thread will not have access to any variables from the main app. This is very similar to the process-forking approach, but is faster because you avoid the overhead of spawning a new process.
  • Do your calculations in native (C++) code, where you're free to do it on a separate thread. Here's a native fibonacci example.
Sign up to request clarification or add additional context in comments.

7 Comments

Ah I think I see. So if I was running a web server and using this function to send the result to the browser, and 2 people connected at a time, then would the code work asynchronously, and start the calculations at the same time?
To be clear, say 100 simultaneous connections hit the server to run this function, would it return to the first person, then run it again and return to the second person and so forth, or would it return to all 100 people at the same time? I thought to get your code to work with asynchronously all you needed was to use callback functions
@nearpoint: There is a single JavaScript thread; you can only do one thing in JS at a time. Thus, it's the former: each request would queue and get a response one at a time. There's nothing inherently magic about making a function use a callback or the fact that you're writing a web server. If you spend a long time in a function, it will block quite literally everything, including the JS code necessary to service HTTP requests.
I guess then I am confused about the advantage of Node.js being non-blocking? I have read many places that with node you can access and search a database while the program continues in a non-blocking fashion. Is the only way to do this if the database is a request to another computer (or another thread), and that the callback will be fired when it is done vs. storing the result into a variable? In this video Node is handling multiple request at once: Ryan Dahls intro to node video: youtu.be/jo_B4LTHi3I?t=20m26s It starts at the spot, how is this possible with what you are saying?
@nearpoint: Because all of those things (DB access, network I/O, etc) do happen on another thread. Your JS code isn't calling into system APIs; instead, you use node's APIs to initiate those calls (which happens behind the scenes in C++ code on a thread pool), and meanwhile your code continues on doing other things. Whenever the API call completes, your code is invoked again when it goes idle. Think of it this way: anything you personally write will run on a single thread. Everything else is done asynchronously and non-blocking.
|
0

You cannot have the functions run truly simultaneously, as if you had multiple threads running in parallel. This is because Javascript is single threaded, not multithreaded. The best you really get is "sorta kinda" parallel operation that really, in practice, isn't parallel.

Comments

0

You may want to give the core cluster module a try which will allow you to run a node process per core. It may work with a single core, but multiple cores is highly recommended for this approach.

Another thing to check out is the async module with the parallel control flow, though this is still applicable to the notion of the single thread.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.