1

Like many before, I came across this diagram describing the architecture of NodeJS and since I'm new to the concept of Asynchronous programming, let me first share with you my (possibly flawed) understanding of Node's architecture.

Node Architecture

To my knowledge, the main application script is first compiled into binary code using Chrome's V8 Engine. After this it moves through Node.JS bindings, which is a low-level API that allows the binary code to be handled by the event mechanism. Then, a single thread is allocated to the event loop, which loops infinitely, continually picks up the first (i.e. the oldest) event in the event queue and assigns a worker thread to process the event. After that, the callback is stored in the event queue, moved to a worker thread by the event-loop thread, and - depending on whether or not the callback function had another nested callback function - is either done or executes any of the callback functions that have not yet been processed.

Now here's what I don't get. The event-loop is able to continually assign events to worker threads, but the code that the worker threads have to process is still CPU blocking and the amount of worker threads is still limited. In a synchronous process, wouldn't it be able to assign different pieces of code to different worker threads on the server's CPU?

Let's use an example:

var fs = require('fs');
fs.readFile('text.txt', function(err, data) {
    if(err) {
        console.log(err);
        } else  {
            console.log(data.toString());
        }
});
console.log('This will probably be finished first.');

This example will log 'This will probably be finished first' and then output the data of the text.txt file later, since it's the callback function of the fs.readFile() function. Now I understand that NodeJS has a non-blocking architecture since the second block of code is finished earlier than the first even though it was called in a later stage. However, the total amount of time it takes for the program to be finished would still be the addition of the time it takes for each function to finish, right?

The only answer I can think of is that asynchronous programming allows for multithreading whereas synchronous programming does not. Otherwise, asynchronous event handling wouldn't actually be faster than synchronous programming, right?

Thanks in advance for your replies.

  • 1
    I'm not going to close this as duplicate yet because the question is structured based on a misconception but please read this answer to another question, it will answer your confusion 100% but will not answer this specific question at all: https://stackoverflow.com/questions/34855352/how-in-general-does-node-js-handle-10-000-concurrent-requests/34857298#34857298 – slebetman Feb 10 '19 at 11:23
  • ... also, read the question to give context to my answer – slebetman Feb 10 '19 at 11:23
  • @slebetman Indeed, it answered my question, thank you. So, for the sake of clarity, a single-threaded event loop leverages other processes' multi-threaded behaviour (e.g. a database), and in doing so, is able to make multiple requests without having to wait for the first request to be processed. In the example above, does that mean that my own CPU has one thread working on the readFile() function and one on the console.log() function? Thank you. – Ryan Wennekes Feb 10 '19 at 11:39
  • Actually that's the difference between blocking and non-blocking programming. With blocking APIs you need two threads to do readFile() and console.log() concurrently. With non-blocking you only need one thread - you register a function that readFile() will run later and do console.log() in the same thread. Later (maybe a few milliseconds, maybe hours) readFile will continue your logic by calling your function - no need for multiple threads – slebetman Feb 10 '19 at 12:54
  • For node.js file I/O are actually implemented as a separate thread but other languages manage to do it in a single thread - Tcl for example. – slebetman Feb 10 '19 at 12:56
  • @slebetman Suppose that file I/O isn't implemented as a separate thread in nodeJS and the application is - as you said ealier - running non-blocking. When the event loop has put the compiled readFile() function in the single working thread it is occupied, right? Would the result look like this? readFile() -> event queue, console.log() -> event queue, callback() -> event queue? This is assuming that the readFile() function takes longer to finish than console.log(). – Ryan Wennekes Feb 10 '19 at 13:50
  • console.log itself is not non-blocking so it is executed immediately. The event "queue" is more of an OS thing, node only manages lists of listener callbacks. So it looks like this readFile(callback) -> store callback in an array, console.log() gets executed, nothing else happens -> enter event loop -> while(select()). Hard disk finish reading and trigger hardware interrupt -> device driver gets executed -> OS notices event from device driver and queues event -> OS process/task manager notices... – slebetman Feb 12 '19 at 23:01
  • ... OS process/task manager notices disk I/O event must be handled now and wakes up node.js process -> select() returns from blocking (gets woken up) so while(select()) can continue -> inside while() event loop node will compare this event with list of callbacks to know what function to call next -> callback gets called... – slebetman Feb 12 '19 at 23:04
  • You may also be interested to read my answer to this question: https://stackoverflow.com/questions/29883525/i-know-that-callback-function-runs-asynchronously-but-why/29885509#29885509 – slebetman Feb 12 '19 at 23:30

0 Answers0