The article discusses the use of worker threads in Node.js to improve performance for CPU-intensive operations, with benchmark results showing significant improvements.
Abstract
The article explores the use of worker threads in Node.js to handle CPU-intensive operations, which can lead to significant performance improvements. The author conducted benchmark tests using a CPU-intensive method and a simple REST endpoint, with Jmeter configuration and an Excel graph to display the results. The tests showed that using worker threads can result in up to 5x faster performance compared to asynchronous methods. The article also discusses the use of worker pools and the impact of context switching on performance. The author concludes that the best number of threads to use is highly related to the machine's CPU architecture and that Node.js does not provide a standard way of attaching a process to a specific CPU.
Bullet points
The article discusses the use of worker threads in Node.js to improve performance for CPU-intensive operations.
The author conducted benchmark tests using a CPU-intensive method and a simple REST endpoint, with Jmeter configuration and an Excel graph to display the results.
The tests showed that using worker threads can result in up to 5x faster performance compared to asynchronous methods.
The article also discusses the use of worker pools and the impact of context switching on performance.
The author concludes that the best number of threads to use is highly related to the machine's CPU architecture and that Node.js does not provide a standard way of attaching a process to a specific CPU.
Achieve the Best Performance: 10x Faster Node.Js With Worker Threads
Confronting highly intensive CPU operations throughput using different worker threads configurations.
I’ve come to know lately that there is the possibility of making JavaScript execute in parallel, I gave Node.JS worker threads a try, and I’m excited about the results I got.
Worker threads make Node run in parallel - how awesome is that?
In the previous article, I’ve shown the difference between Spring-Boot and Node-JS performance when it comes to handling database-intensive requests, with just one CPU-intensive request in the loop of the rest calls.
In this article instead, I wanted to focus only on CPU-intensive operations.
The recipe for the benchmark is very simple, we just need:
One CPU-intensive method:
One simple REST endpoint to call:
Some Jmeter configuration:
8 different HTTP request samplers
And the CHART is ready.
Excel graph showing the awesome performance gains I’ve got using WorkerThreads!
Let me explain the results above.
Calling the REST endpoints with 10 concurrent threads looping 10 times for a total of 100 calls, resulted in the ASYNCH method running with an average of 15K milliseconds.
If we instead use WORKERS creating a new worker for each call, the results are already AWESOME, 3918 milliseconds, almost 5x faster.
Let’s start optimizing, re-using the worker for each call, simply moving line 11 of the previous gist on line 8. We get 1599 milliseconds. This is really good.
When instead I’ve used some already made pool of workers (I’ve tried “node-worker-threads-pool” and “poolifier”) performance DROPPED to circa 7K milliseconds; it’s still good but not as good as having a simple worker pre-created. I somehow have the feeling that these libraries do not provide the capability of pre-creation for workers, dropping performance significantly.
So I thought: What if we use a simple PRE-BUILT array of workers? Well, I’ve got the values in the latest 3 columns. The first one is the performance results of using 2 workers, the second one 4 and the latest 8. Very strange: the more worker-threads we use, the more performance drops.
I think that this is caused by the threads continuously executing context-switch. In fact, if we increase the number of CPU operations for one call, forcing the computation to remain more time running on a single worker, using more than one thread results in performance optimization.
As you can see from the previous graph, more threads do not mean better performance. The best number of threads to use is highly related to the machine’s CPU architecture the application is running on — always thanks to the previously mentioned context-switching.
Unfortunately, Node.JS does not provide a standard way of “attaching” a process on a specific CPU, but the processor-affinity is completely handled by the OS, resulting in somehow less control given to the programmer when it comes to multithreading.