And Lost be the day to us in Which a measure hath not been danced.
And false be every truth which hath not had laughter along with it.
— Niezsche
As we know, javascript is running on a single process, which brings a question, how can we get the multi-core CPU fully work?
Multi-process structure
Fortunately, node offers us child_process moudle so that we can easily create multi-porcess and work them together.
First of all, we create a js file named parent.js which will create a child process and listen to it.
//parent.js
var cp = require('child_process'),
n = cp.fork('test/child.js');
n.on('message', function(m) {
console.log('parent got message: ', m);
});
n.send({hello: 'world'});
Note that fork
creates a new process whice has all the mehods in a normal ChildProcess with a build-in communication channel(Inter-Process communication channel ). So we can write to a child using send
method.
what the child process does is, as same as the parent process’s, listening to the parent process. When there is message come, they print the message out.
process.on('message', function(m) {
console.log('child got meaage: ', m);
});
process.send({foo: 'bar'});
Running command node parent.js
we can get the following:
child got meaage: { hello: 'world' }
parent got message: { foo: 'bar' }
Here we go, now we have two process runing and communicating.
the handler delivery
Only text message sent is probably not enough. However, we can also send TCP server or socket object as handler to another process.
//parent.js
var cp = require('child_process'),
child = cp.fork('test/child.js');
var server = require('net').createServer();
server.on('connection', function(socket) {
socket.end('handled by parent\n');
});
server.listen(1337, function() {
child.send('server', server);
});
the child.js would look like this:
process.on('message', function(m, server) {
if(m === 'server') {
server.on('connection', function(socket) {
socket.end('handled by child\n');
});
}
});
Now the server is shared between the parent and child. That means connections can be handled by either of them. Running node parent.js
and we test it by curl "http://localhost:1337/"
the result can be both.
What if we seperate the tasks of parent process and child process? Once the handle is sent to child process from parent process, we close the server so it no longer listens to the port.
//parent.js
var cp = require('child_process'),
child1 = cp.fork('test/child.js'),
child2 = cp.fork('test/child.js');
var server = require('net').createServer();
server.listen(1337, function() {
child1.send('server', server);
child2.send('server', server);
server.close();
});
server.on('close', function(){
console.log('server closed');
})
change child.js a litte:
var http = require('http');
var server = http.createServer(function(req,res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('handled by child, pid is ' + process.pid + '\n');
});
process.on('message', function(m, tcp) {
if(m === 'server') {
tcp.on('connection', function(socket) {
server.emit('connection', socket);
});
}
});
Now we have two child processes to listen to the port. Once TCP connection is emited, we emit http connection and send client socket object to http server to do something.
Notice that tcp server is shard by more than one child process, It’s possible that the request is handled by differnt child process. But it’s fine. The process service is preemptive. Depends how busy the process is, the less busy one will handle the request.
Even if node is running on a single process, with multi-process running, we can still better using multi-core CPU and likely to handle high loads situation.