Using worker_threads in Node.js
This is a beginner’s guide to using worker_threads
in Node.js. It does not assume you already understand Web Workers. (The API for worker_threads
is based on Web Workers.) Let’s dive in.
Loading the module
worker_threads
became available in Node.js 10.5.0. Prior to Node.js 11.7.0, you could not access the module unless you started node
with the --experimental-worker
flag.
$ node -e "require('worker_threads'); console.log('success');"
internal/modules/cjs/loader.js:605
throw err;
^Error: Cannot find module 'worker_threads'
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:603:15)
at Function.Module._load (internal/modules/cjs/loader.js:529:25)
at Module.require (internal/modules/cjs/loader.js:657:17)
at require (internal/modules/cjs/helpers.js:22:18)
at [eval]:1:1
at Script.runInThisContext (vm.js:123:20)
at Object.runInThisContext (vm.js:312:38)
at Object.<anonymous> ([eval]-wrapper:6:22)
at Module._compile (internal/modules/cjs/loader.js:721:30)
at evalScript (internal/bootstrap/node.js:720:27)
$
$
$ node --experimental-worker -e "require('worker_threads'); console.log('success');"
success
$
As of this writing, worker_threads
are an experimental feature. Theoretically, that means breaking changes could happen at any time and you should not use worker_threads
in production.
What are they good for?
As the documentation says:
Workers are useful for performing CPU-intensive JavaScript operations; do not use them for I/O, since Node.js’s built-in mechanisms for performing operations asynchronously already treat it more efficiently than Worker threads can.
worker_threads
are more lightweight than the parallelism you can get usingchild_process
or cluster
. Additionally, worker_threads
can share memory efficiently.
Hello world!
In the following example, Worker
is the constructor for a worker. It requires an argument which is the path to a file containing the code for the worker to execute. In this case, we send it __filename
so that the code that launches the worker and the code for the worker itself are in the same file. The constructor also takes an optional second options
argument, but we do not use it here.
To differentiate whether we are in the main thread (which will launch the worker) or the worker itself, we use isMainThread
. It is true
if we are in the main thread (that is, not in a worker) and false
if we are in a worker.
Once the worker is created, we listen (in the main thread) for the message
event on the worker and use console.log()
to print whatever is sent.
Lastly, to send a message from the worker to the main thread, we use parentPort.postMessage()
.
Put this code in a file called threads-example.js
, invoke it with node
(and the --experimental-worker
flag if you are not running Node.js 11.7.0 or newer), and the output should be Hello world!
.
$ node threads-example.js
Hello world!
$
Calculating Primes
Now let’s do something a little more interesting. Without worker_threads
, here is how you might calculate all the prime numbers less than 10,000,000:
The code above was ported from a C# implementation at https://stackoverflow.com/a/34429272/436641. The important thing to know is that the generatePrimes()
function does CPU-intensive work.
On my laptop, running the code above with the time
utility reports results along the lines of:
real 0m17.209s
user 0m15.589s
sys 0m0.242s
Now let’s see what happens with worker_threads
:
The new concept here is workerData
. You set a value for the workerData
option when invoking the Worker
constructor. The value of workerData
is cloned and available in the worker thread as require('worker_threads').workerData
.
Running this script and passing it 2
on the command line (as the number of threads to use) yields far better performance than the single-threaded version:
real 0m7.881s
user 0m12.832s
sys 0m0.162s
Next Steps
- Using worker_threads in Node.js Part 2
- To find out more about
worker_threads
, I’d recommend the documentation as your next stop! Good luck and have fun!
Thanks, Anna Henningsen, for reviewing a draft of this post.