Handling blocking operations in Node
Node Tips and Tricks for faster APIs (2)
In the previous part of this article series, we discussed using clusters to scale out your Node APIs, taking advantages of multiple processor cores on a single machine.
While a cluster fork (hehe) makes a clone of the current process, a child process is a separate process that is started by a Node process.
As long as a program can be executed directly, it can be run as a child process within a parent Node process.
A parent process can listen to events emitted by the child like stdout
, stdin
, and stderror
among others. It can also supply standard input to the child, to control its execution flow.
Example
Let’s take a quick example showing a Node program invoking the ls
unix program which lists all the files and folders within the current working directory.
Open a terminal (unix)
Type
node
and press ENTER to begin the Node REPLCopy and paste the following script
Using Child Processes for complex tasks
But what do all these have to do with building faster and more efficient Node apps?
What if we could shift our computation of prime numbers to a child process, so our main process is free to handle other requests?
Would this improve our API performance?
To manage our child-processes, we will make use of the node-worker-farm package.
So, create a new branch from our repo called child-process
and run
npm i -s node-worker-farm
in the terminal.
Located here.
We define the function that generates the prime numbers in a separate file called worker.js
.
It takes a
max
argument which determines the upper limit of the prime numbers our API responds with.It also accepts a callback function with an error as its first parameter, and the result array as its second. We use a try-catch statement to handle errors.
At each request, we spin up a child-process to handle the computation while our main thread (event loop) is free to respond to other requests.
Here are our results …
Let’s compare with our results from the previous article.
(no-clusters) vs (clusters) vs (child-process)
- min: 13ms vs 13.5ms vs 17.7ms
- max: 1443.1ms vs 1606.5ms vs 521.6ms
- median: 610.3ms vs 290.7ms vs 331.9ms
- p95: 683.7ms vs 560.6ms vs 403.3ms
- p99: 1256.4ms vs 719.5ms vs 434.5ms
Whoop! Whoop! 🎉🍾🥂
Using child-processes with a single parent process outperforms single-process
and clusters
modes in our simple prime numbers API.
However, it is worth mentioning that real world applications are hardly ever this simple. Throwing child-processing at a bottleneck may not solve the problem as easily as one would think.
You should leverage child processes when your bottleneck exists because of computation intensity that is guaranteed to block the event loop.
In the next and final article in this series, we will be considering two more ways to improve your API performance.
https://medium.com/@mykeels/interrupts-and-request-memoization-23cfe925b0ec