Node.js 10.5 release: multi-thread out of the box
Last week there was a release of Node.js version 10.5.0, containing an innovation, whose importance can not be overestimated - support for multithreading in the form of the module worker_threads . Immediately I will make a reservation. The API is in the experimental stage and therefore it can change, but now you can make a first impression and get an idea of the principles and technologies laid down in its foundation. And if you have the desire, then take part in interface finalization, writing code or fixing bugs (list of issues ).
Appearance history
Throughout the life of Node.js, the only way to parallelize the calculations was to launch a new process, for example, using the cluster module. For many reasons, this approach does not suit the developers, in particular, because it leads to a slow loading into memory of the computer of the executable Node.js code with all the built-in modules, which is an inefficient way of spending resources.
Nevertheless, the discussion of the introduction of multithreading to Node.js always rested on the complexity of V8 and a huge number of unknowns: how to connect native modules, share memory, communicate between threads, and so on. And while the developers were looking from which side to approach the topic on the web, the Worker API was successfully implemented , which became the benchmark in the initial stages. Development began with the efforts of addaleax and was picked up by the community.
During the year, active work was carried out, during which the design requirements were concretized and the API acquired its own Node.js-specific features, and the module itself was named worker_threads. Below I briefly describe worker_threads in general, and for detailed study I advise you to visit the official documentation page .
Description
As mentioned above, the goal of this development is to improve performance by distributing the load across separate threads in a single process, instead of starting multiple processes. Therefore, threads will support the connection of all modules accessible to the main process (currently, native modules are not supported).
As in the Worker API, the interaction between the main and child threads is carried out by transferring objects (Transferrable) via postMessage, which avoids simultaneous access problems, although it requires additional memory accesses to copy data. At the same time, objects like SharedArrayBuffer retain their behavior and do not cause relocation.
MessageChannel and MessagePort were taken from the WebAPI , which allows you to create isolated message exchange channels and transfer them between threads.
In order to try worker_threads in business, you need to specify a special flag when starting the process:
node --experimental-worker main.js
Example
Since the API can still change, I will not describe it, but I will give an example of an exchange of messages between the parent and child threads, in which the child thread reports its threadId, via MessagePort and finishes its work.
Main thread
Sample code of the main thread:
// main.jsconst {Worker} = require('worker_threads');
const worker = new Worker(__dirname + '/worker.js');
worker.on('online', () => {
console.log('Worker ready');
});
worker.on('message', (msg) => {
console.log('Worker message:', msg);
});
worker.on('error', (err) => {
console.error('Worker error:', err);
});
worker.on('exit', (code) => {
console.log('Worker exit code:', code);
});
Child thread
A child thread lives until its event loop (event loop) is empty. Thus, immediately after the execution of the code from the worker.js
stream will be automatically closed. To communicate with the parent, use parentPort:
// worker.jsconst {threadId, parentPort} = require('worker_threads');
parentPort.postMessage(`Hello from thread #${threadId}.`);
// Exit happens here
In a child thread, the process object is redefined, and its behavior is somewhat different from the process behavior in the parent thread. In particular, it is not possible to respond to SIGNINT signals, change the values process.env
, and the call process.exit
will stop only the worker, but not the whole process.
Conclusion
Workers will greatly simplify the creation of applications that require interaction between concurrently executed sections of code and, most importantly, makes communication and flow control the most obvious way. It will also avoid platform-specific restrictions caused by the difference between Windows and Unix. I am sure that the opportunities will attract new developers who have not yet made a choice in favor of Node.js. In the meantime, continue to monitor the changes and connect to the API development process in the repository .
Links
- Documentation on worker_threads .
- Author photo Paul Smith.