Use Multiple Threads in Node like a PRO
Akash Shyam
Posted on March 26, 2021
Time consuming and software intensive programs cannot be run on the main thread. With Piscina, create new threads with absolute ease.
Why Should You Care?
While building APIs, most of us have hashed passwords before storing it in our database(if you haven't... please do it). We often tend to go lightly on our hashing so that it does not affect performance. With multiple threads, this can be done separately without blocking the main thread and leaving the user hanging.
Example
Let's setup an NPM project:
npm init -y
Install piscina:
npm i piscina
Create an index.js
file and add the following code:
const path = require('path');
const Piscina = require('piscina');
const piscina = new Piscina({
filename: path.resolve(__dirname, 'worker.js')
});
(async function() {
const result = await piscina.runTask({ a: 4, b: 6 });
console.log(result); // Prints 10
})();
We've created a new piscina worker
and passed in the absolute path to the worker. Then, in an async function, we've allotted a task to our worker.
Now, for our worker.... let's create a worker.js
file:
module.exports = ({ a, b }) => {
return a * b;
};
Our workers can also be a promise
.
const { promisify } = require('util');
// Make setTimeout() a promise
const timer = promisify(setTimeout);
module.exports = async ({ a, b }) => {
// Fake some async code
await timer(() => {
console.log('1 second later');
} ,1000);
return a * b;
};
What we've seen is pretty straightforward and not very difficult to implement on our own.... here's where piscina start's to shine:
- Efficient Communication Between threads
- Task Cancellation
- Delaying Availability
- Custom Task Queues
- Statics for run and wait times
- Async Tracking
- Support for Typescript(yay!), common JS and ESM
We'll look at most of this throughout the post.
Cancellation
For this, we'll need use the events
package.... this comes by default so no need to install anything. The event package gives us an EventEmitter
which we can use to send events. Our worker listens to the abort
event, stops executing and throws an error to let us know that it was successfully cancelled.
const path = require('path');
const Piscina = require('piscina');
const EventEmitter = require('events');
const piscina = new Piscina({
filename: path.resolve(__dirname, './worker.js'),
});
(async function () {
const eventEmitter = new EventEmitter();
try {
const task = piscina.runTask({ a: 4, b: 5 });
eventEmitter.emit('abort');
await task;
} catch (error) {
console.log('Task cancelled');
}
})();
If you look carefully, you will find that we haven't immediately awaited our task. If we don't do this, then by the time the abort
event is emitted, the task would have finished executing.
This is by no means a complete list of what piscina can do.... checkout the official docs here.
That's it for now, I hope you guys liked this post. If you did please like it and follow me. Bye đź‘‹
Posted on March 26, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.