Nodejs minimal introduction tutorial (iii) : processes

  • 2020-03-30 04:10:04
  • OfStack

Node has multiple threads of its own, but JavaScript running on v8 is single-threaded. Node's child_process module is used to create child processes through which we can make full use of the CPU. Example:


var fork = require('child_process').fork;
//Gets the number of cpus on the current machine
var cpus = require('os').cpus();
for (var i = 0; i < cpus.length; i++) {
    //Generate a new process
    fork('./worker.js');
}

Here are a few process creation methods, including fork:

1. Spawn (command, [args], [options]), which starts a new process to execute the command command
2. Exec (command, [options], callback), which starts a new process to execute the command command
3. ExecFile (file, [args], [options], [callback]), which starts a new process to execute the executable file
4. Fork (modulePath, [args], [options]), starts a new process to execute a JavaScript file module, at which point the Node child process is created

Communication between Node processes

The parent process


// parent.js
var fork = require('child_process').fork;
//Fork returns the child process object n
var n = fork('./child.js');
//Handle the event message
n.on('message', function(m) {
    //Received a message
from the child process     console.log('got message: ' + m);
});
 
//Sends a message
to the child process n.send({hello: 'world'});

The child process


// child.js
//Handle the event message
process.on('message', function(m) {
    console.log('got message: ' + m);
});
 
//A send method exists for process to send a message to the parent process
process.send({foo: 'bar'});

It is important to note that the send method here is synchronous, so it is not recommended to send a large amount of data (pipe can be used as a substitute for, see: (link: http://nodejs.org/api/all.html#child_process_child_process_spawn_command_args_options)).
In special cases where the CMD attribute value in the message contains the NODE_ prefix (for example: {CMD: 'NODE_foo'} message), the message is not committed to the message event (instead of the internalMessage event) and is used internally by the Node.

The prototype of send method is:


send(message, [sendHandle])

Here, the sendHandle (handle) can be used to send:

1.net.Native, native C++ TCP socket or pipeline
2.net.Server, TCP server
3. net.socket, TCP socket
4. Dcgram.Native, Native C++ UDP socket
5. Dgram. Socket, UDP Socket

When send sends the sendHandle, it doesn't actually (and can't) send the JavaScript object directly. Instead, it sends the file descriptor (which ends up being sent as a JSON string) that other processes can use to restore the corresponding object.

Now for an example:

The parent process


// parent.js
var fork = require('child_process').fork;
 
var n = fork('./child.js');
 
var server = require('net').createServer();
server.listen(7000, function() {
    //Sends TCP server to child process
    n.send('server', server);
}).on('connection', function() {
    console.log('connection - parent');
});

The child process


process.on('message', function(m, h) {
    if (m === 'server') {
        h.on('connection', function() {
            console.log('connection - child');
        });
    }
});

Accessing this program through port 7000, the resulting output can be either the connection parent or the connection child. Here the child and parent processes are both listening on port 7000. Normally, multiple processes listening to the same port causes an EADDRINUSE exception, but in this case, two different processes use the same file descriptor, and Node's underlying listening to the port sets the SO_REUSEADDR option on the socket, which allows the socket to be reused between different processes. When multiple processes listen on the same port, the file descriptor can only be used by one process at a time, and the use of the socket by these processes is preemptive.

The cluster module

Cluster module is added to Node's v0.8, which makes it easy to build a set of processes listening to the same port on a physical machine. Example:


var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;
 
//Check if the process is a master process
if (cluster.isMaster) {
    for (var i = 0; i < numCPUs; ++i)
        //Generate a new worker process (only the master process can be called)
        cluster.fork();
 
    cluster.on('exit', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died');
    });
} else {
    http.createServer(function(req, res) {
        res.writeHead(200);
        res.end('hello worldn');
    }).listen(8000);
}

We call the listen method in the worker process, and the listening request will be passed to the master process. If the master process already has a listening server that meets the requirements of the worker process, then the handle of this server will be passed to the worker. If it does not exist, the master process will create one and then pass the handle to the worker process.

More detailed documentation about cluster: (link: http://www.nodejs.org/api/cluster.html)


Related articles: