process

Node does not allow multithreading, but it does allow child processes. The child_process module provides a service for creating a process without affecting the Node event loop

Multiple processes

Each process occupies one CPU. You can view the CPU core as follows

let os = require('os').cpus().length;
console.log(os)
Copy the code

There is also the concept of clustering. In cpu-intensive situations, Node is not very well suited for complex logical operations, which need to be done by another process, which needs to communicate with each other to retrieve data

Cpua CPU can host many processes. A service occupies one process, and one process is connected to the CPU

We want our service to be multi-process, and multiple processes can occupy multiple cpus

  • The main process daemon
  • Child process worker process
  • A service can start multiple processes (load balancing)

A node process contains a main thread

The cluster

A node can be divided into multiple threads, usually by CPU, within a process

Maybe we’ll have a process that crawls and another process that writes pages, so how do we create a child process that communicates with each other

Exec execFile execFile is based on spawn
// Only the main process can open multiple child processes
let { spawn } = require('child_process');
let path = require('path');
// spawn a small process
// Processes cannot communicate with each other by default

let child = spawn('node'['1.test.js'.'a'.'b'.'c'] and {Run the node command
  cwd:path.join(__dirname,'test'),  // Get the current working directory
  Process. stdin 0 process.stdout 1 process.stderr 2
  stdio:[0.1.2]// Pipe does not write the default pipe type. Pipe passes these three attributes from the parent process to the child process (shared).
});
// Process communication
child.stdout.on('data'.function(data){
    console.log(data.toString());
})
child.on('error'.function (err) {
  console.log('err');
});
child.on('exit'.function () {
  console.log('exit')});Copy the code

Process of communication

//1.test.js
process.argv.forEach(element= > {
    process.stdout.write(element);
});

Copy the code

demand

  • Create three processes
  • The main process is responsible for creating two processes
  • Pass the parameters of the first process to the second process
  • The second process writes to the file
//1.js
let { spawn } = require('child_process');
let path = require('path');

// Open two child processes
let child1 = spawn('node'['1.test.js'.'a'.'b'.'c'] and {// Execute the node command to execute the file and parameters
  cwd: path.join(__dirname,'.. '.'pro')  // Get the current working directory
});
let child2 = spawn('node'['2.test.js'.'a'.'b'.'c'] and {// Execute the node command to execute the file and parameters
    cwd: path.join(__dirname,'.. '.'pro')  // Get the current working directory
});/ / asynchronous
child1.stdout.on('data'.function(data){
    // Get the data returned by process 1 and send it to process 2
    child2.stdout.write(data)
})
Copy the code
//1.test.js
process.argv.slice(2).forEach(arg= > {
    process.stdout.write(arg);
});

//2.test.js
let fs = require('fs');
let ws = fs.createWriteStream('./1.txt');

process.stdout.on('data'.function(data){
    ws.write(data);
})
setTimeout(function(){
    process.exit(); // Exit the process. The main process also exits when it finishes executing
},1000)
Copy the code

For the upper method we need to keep on and we need to consider whether stDIN or stdout, we can create channels between processes

Process of communication

//2. Js fork
let {spawn} = require('child_process');
let path = require('path');

let child = spawn('node'['ipc.js'] and {cwd: path.join(__dirname,'.. '.'pro'),stdio: ['pipe'.1.'pipe'.'ipc']
  //ignore no child process data, pipe pipe, null, can add IPC communication
});

child.send('Am I beautiful?');
child.on('message'.function (data) {
  console.log(data);
  child.kill();/ / kill process
});
//ipc.js
process.on('message'.function (data) {
    process.send(data +  'You're beautiful')});Copy the code

The main process controls the child process, but if the main process hangs, the child process also hangs, and we give up control at execution, as follows

let { spawn } = require('child_process');
let path = require('path');
let fd = require('fs').openSync('./100.txt'.'w');

// The independent process stdio should be set to have no relationship with the parent process
let child = spawn('node'['ipc.js'] and {cwd: path.join(__dirname,'.. '.'pro'),
  stdio: ['ignore', fd , 'ignore'].detached:true // Ready to give up
});
child.unref(); // Indicates that the child will continue to allow the parent process to die

//ipc.js
setInterval(function(){
    process.stdout.write('hello')},3000)
Copy the code

fork

The usage of fork is basically the same

let { fork } = require('child_process');
let path = require('path');
let child = fork('ipc.js'['a'.'b'] and {// The default node does not need to write node
  cwd: path.join(__dirname,'.. '.'pro'),
  silent: false // Quiet, stdio[ignore*3,'ipc']
})

// The default ipc mode is to send messages directly
child.send('hello');

child.on('message'.function (data) {
  console.log(data);
})
Copy the code

Implement fork with spawn

// Execute module, parameter, object
function fork(modulePath, args, options = {}) {
  if (options.silent) {
    options.stdio = ['ignore'.'ignore'.'ingore'.'ipc']}else {
    options.stdio = [0.1.2.'ipc']}return spawn('node', [modulePath, ...args], { ... options }) }Copy the code

The cluster

A cluster is just a simplification of processes. One process can have one thread. We want to have two processes listening on one service.

/ / 3. Js main process
let http = require('http');
let { fork } = require('child_process');
let path = require('path');

let child = fork('http.js', { 
    cwd: path.join(__dirname,'.. '.'pro')})let server = http.createServer(function(res,req){
    res.setEncoding('Parent process processing request');
}).listen(3000)


child.send('server',server);// The second parameter of send can only be used for HTTP or TCP services

// Child http.js
let http = require('http');
// The child process helps handle requests from the parent process by listening not only for port numbers, but also for another service
process.on('message'.function (msg, server) {
    http.createServer(function(res,req){
        res.setEncoding('Child process request');
    }).listen(server)
})


// Start the service cilent.js
let http = require('http');
for(var i = 0; i<1000; i++){ http.get({port: '3000'.hostname: 'localhost'
  },(res)=>{
    res.on('data'.function (data) {
      console.log(data.toString()); })})}Copy the code

This is easy to write, we can use NET

/ / 3. Js main process
let net = require('net');
let { fork } = require('child_process');
let path = require('path');

let child = fork('socket.js', { 
    cwd: path.join(__dirname,'.. '.'pro')})let server = http.createServer(function(socket){
    if(Math.random > 0.5){
        socket.write('father')}else{
        child.send('socket',socket)
    }
}).listen(3000)

// Child process socket.js

let http = require('http');
// The child process helps handle requests from the parent process by listening not only for port numbers, but also for another service
process.on('message'.function (msg, server) {
    if(masg == 'socket'){
        socket.write('child')}})// Start the serviceUse the putty we talked about earlierCopy the code

ExecFile Specifies the command to be executed. / Exec specifies the command to be executed

  • Spawn is asynchronous and receives data on send on message
  • ExecFile can wait for the results to be output together
  • No parameters are supported. Only commands can be executed, but files can also be executed
// let {execFile} = require('child_process');

// execFile('node',['--version'],function (err,stdout,stderr) {
// console.log(stdout);
// })
// execFile('ls',['-1'],function (err,stdout,stderr) {// Display a list of execfiles
// console.log(stdout);
// })
let {exec} = require('child_process'); 
// webpack --open
// Execute some commands
exec('start http://localhost:3000'.function (err, stdout, stderr) {
  console.log(stdout);
});
Copy the code

Cluster cluster

More processes are not always better, depending on the number of CPU cores

let {cluster} = require('child_process');
// It is possible to communicate via IPC, and setUpMaster is used
if(cluster.isMaster){
    // Create a process in the main branch and return the process
    let worker = cluster.fork();// A command is issued to execute the current file
    console.log('Parent process')}else{
    console.log('Child process')
    process.exit();
    process.disconnect();
}
cluster.on('disconnect'.function(){ // Listen for fork events
    console.log(disconnect)
})
cluster.on('fork'.function(worker){ // Listen for fork events
    console.log(worker.id)
})
cluster.on('exit'.function(){ // Listen for fork events
    console.log(exit)
})
Copy the code

Open the process according to the CPU

let {cluster} = require('child_process');
let cpus = require('os').cpus().length;
let http = require('http')
let path = require('path')
// It is possible to communicate via IPC, and setUpMaster is used
if(cluster.isMaster){
    console.log('Parent process')
    for(let i=0; i<cpus.length; i++){ cluster.fork(); }}else{
    console.log('Child process')
    http.createServer(function(res,req){
        res.end('ok' + process.pid)
    }).listen(3000)}Copy the code

setUpMaster

let {cluster} = require('child_process');
let cpus = require('os').cpus().length;
let http = require('http')
let path = require('path')
// Can communicate via IPC, want to use setUpMaster
if(cluster.isMaster){
    cluster.setUpMaster({
        stdio:'pipe'.// Pipeline communication
        exec:path.join(__dirname,'subprocess.js') // Write separately from the child process
    })
    console.log('Parent process')
    for(let i=0; i<cpus.length; i++){ cluster.fork(); } } cluster.on('fork'.function(worker){ // Listen for fork events
    console.log(worker.id)
})

//subprocess.js
let http = require('http')
console.log('Child process')
http.createServer(function(res,req){
    res.end('ok' + process.pid)
}).listen(3000)
Copy the code