Node.js Event Model
Node.js has gained lot of traction in the last few years and many high performance sites are today using it. When we started with it, I wanted to understand what’s it that makes node.js so high performant, over and above the regular web servers, which were created with the purpose of being able to handle loads of incoming requests.
The answer lies in the core of node.js that uses a single thread for its main execution and passes on the work to asynchronous functions. In the world of multitasking and multi-core CPU machines, this come as a surprise, but then when you look at the cost of creating all these parallel threads vs handling all incoming requests in a single thread, you suddenly realize the benefits, and is very clearly visible also in the performance it delivers.
As I thought about this, I realized that this concept isn’t new but is something that is at the heart of windows programming, something I had learnt back in 1995. We had started programming on Windows for Workgroups. The OS was multi-tasking, but non-preemptive. What this means that while it was capable of running multiple tasks (by using time slicing algorithms), it wasn’t able to interrupt a running code on its own. The applications had to be good Windows citizens and had to be written in a manner that they would relinquish control themselves when idle and OS could then take over and run other code.
To manage this, the Windows program was mainly running using an event queue on a single thread, called its primary thread. If there was an event (call it task, if you may), it would get picked up and executed and if there was nothing in the queue, the code would continue to wait. It was at this wait time that the OS was able to take control and do other actions. The event that would get picked up would be passed to what was called as Windows Procedure and it would then do the necessary processing of the event. If required, the code here could spin off additional threads to do async operations or it could process it on the primary thread itself. The drawback of doing lot of work on primary thread what that the same thread was used to update the user interface and this would get stalled, giving a perception of hung application.
If you think about it, the processing that node.js is doing, isn’t different from this early programming concept. The event queue that Windows used, was a priority queue and messages would higher priority would get picked up first (PostMessage with priority). For some critical tasks, there was mechanism to by-pass this queue and directly get the tasks done as well (SendMessage).
It is interesting to see that the underlying core principals don’t often change. What changes is the outer shell, the technology layers on the top, to build on these core principals.