Using worker_threads in Node.js
Loading the module
worker_threads became available in Node.js 10.5.0. However, you cannot access the module unless you start
node with the
$ node -e "require('worker_threads'); console.log('success');"
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 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');"
As you might infer from the
worker_threads are an experimental feature for now. Theoretically, that means breaking changes could happen at any time and you should not use
worker_threads in production.
There is a pull request to remove the
--experimental-worker flag and make
worker_threads available by default. So that will likely be coming to an upcoming Node.js version soon. (At the time of this writing, the current version of Node.js is 11.6.0.)
What are they good for?
As the documentation says:
worker_threads are more lightweight than the parallelism you can get using
worker_threads can share memory efficiently.
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
Put this code in a file called
threads-example.js, invoke it with
node and the
--experimental-worker flag, and the output should be
$ node --experimental-worker threads-example.js
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:
Now let’s see what happens with
The new concept here is
workerData. You set a value for the
workerDataoption when invoking the
Worker constructor. The value of
workerData is cloned and available in the worker thread as
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:
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.