1. 进程 #

1.1 进程对象属性 #

process.stdin.resume();
process.stdin.on('data',function(chunk){
  process.stdout.write(`进程接收到数据: `+chunk);
});
process.argv.forEach((val,index,ary)=> console.log(index,val));

1.2 memoryUsage方法 #

process.memoryUsage()

stack

1.3 nextTick方法 #

nextTick方法用于将一个函数推迟到代码中所书写的下一个同步方法执行完毕或异步方法的回调函数开始执行前调用

1.4 chdir #

chdir方法用于修改Node.js应用程序中使用的当前工作目录,使用方式如下

process.chdir(directory);

1.5 cwd 方法 #

cwd方法用返回当前目录,不使用任何参数

console.log(process.cwd());

1.6 chdir 方法 #

改变当前的工作目录

console.log(`当前目录: ${process.cwd()}`);
process.chdir('..);
console.log(`上层目录: ${process.cwd()});

1.7 exit 方法 #

退出运行Node.js应用程序的进程

process.exit(0);

1.8 kill方法 #

用于向进程发送一个信号

process.kill(pid,[signal]);

1.9 uptime #

返回当前程序的运行时间

process.uptime()

1.10 hrtime #

测试一个代码段的运行时间,返回两个时间,第一个单位是秒,第二个单位是纳秒

let fs = require('fs);
let time = process.hrtime();
let data = fs.readFileSync('index.txt');
let diff = process.hrtime(time);
console.log(`读文件操作耗费的%d秒`,diff[0]);

1.11 exit事件 #

当运行Node.js应用程序进程退出时触发进程对象的exit事件。可以通过指定事件回调函数来指定进程退出时所执行的处理。

process.on('exit',function(){
    console.log('Node.js进程被推出);
});
process.exit();

1.12 uncaughtException事件 #

当应用程序抛出一个未被捕获的异常时触发进程对象的uncaughtException事件

process.on('uncaughtException',function(err){
  console.log('捕获到一个未被处理的错误:',err);
});
notExist();

1.13 信号事件 #

process.stdin.resume();
process.on('SIGINT',function(){
    console.log('接收到SIGINT信号');
});

2. 子进程 #

默认情况下,子进程的stdin,stdout,stderr导向了ChildProcess这个对象的child.stdin,child.stdout,child.stderr流,

let spawn = require('child_process').spawn;
sapwn('prg',[],{stdio:['pipe','pipe',process.stderr]});
let spawn = require('child_process').spawn;
spawn('prg',[],{stdio:'inherit'});

2.1.2 close #

2.1.3 exit #

child.kill([signal]);

2.1.6 案例 #

  1. spawn.js
    let path = require('path');
    let {
     spawn
    } = require('child_process');
    //默认情况下,子进程的stdin,stdout,stderr导向了ChildProcess这个对象的child.stdin,child.stdout,child.stderr流,
    //这和设置stdio为['pipe', 'pipe', 'pipe']是一样的
    let p1 = spawn('node', ['test1.js', 'a'], {
     cwd: path.join(__dirname, 'test1')
    });
    let p2 = spawn('node', ['test3.js'], {
     cwd: path.join(__dirname, 'test3'),
     stdio: 'pipe'
    });
    //监听test1.js脚本子进程对象的标准输出的data事件,把数据写给p2
    p1.stdout.on('data', function (data) {
     console.log('P1:子进程的标准输出:' + data);
     p2.stdin.write(data);
    });
    p1.on('error', function () {
     console.log('p1:子进程1开启失败');
    });
    p2.on('error', function () {
     console.log('p2:子进程2开启失败');
    });
    
  2. test1.js

    process.stdout.write('p1:子进程当前工作目录为:' + process.cwd() + '\r\n');
    process.stdout.write('p1:' + process.argv[2] + ' \r\n');
    
  3. test2.js

    let fs = require('fs');
    let path = require('path');
    let out = fs.createWriteStream(path.join(__dirname, 'msg.txt'));
    process.stdin.on('data', function (data) {
     out.write(data);
    });
    process.stdin.on('end', function () {
     process.exit();
    });
    

2.1.7 detached #

let count = 10;
let $timer = setInterval(() => {
    process.stdout.write(new Date().toString() + '\r\n');
    if (--count == 0) {
        clearInterval($timer);
    }
}, 500);
`

2.2 fork开启子进程 #

child_process.fork(modulePath,[args],[options]);

2.2.1 发送消息 #

child.send(message,[sendHandle]);//在父进程中向子进程发送消息
process.send(message,[sendHandle]);//在子进程中向主进程发送消息

当父进程收到子进程发出的消息时,触发子进程的message事件

child.on('message',function(m,setHandle){
  //TODO事件回调函数代码
});

5.fork.js

let {
    fork
} = require('child_process');
let path = require('path');
let child = fork(path.join(__dirname, 'fork.js'));
child.on('message', function (m) {
    console.log('父进程接收到消息:', m);
    process.exit();
});
child.send({
    name: 'zfpx'
});
child.on('error', function (err) {
    console.error(arguments);
});

fork.js

process.on('message', function (m, setHandle) {
    console.log('子进程收到消息:', m);
    process.send({
        age: 9
    });
})

2.2.2 silent #

在默认情况下子进程对象与父进程对象共享标准输入和标准输出。如果要让子进程对象用独立的标准输入输出,可以将silent属性值设置为 true forkslient.js

let {
    fork
} = require('child_process');
let path = require('path');

let p1 = fork('node', [path.join(__dirname, 'fork1.js')], {
    silent: true
});
let p2 = fork('node',path.join(__dirname, 'fork2.js'));
p1.stdout.on('data', function (data) {
    console.log('子进程1标准输出:' + data);
    p2.send(data.toString());
});
p1.on('exit', function (code, signal) {
    console.log('子进程退出,退出代码为:' + code);
});
p1.on('error', function (err) {
    console.log('子进程开启失败:' + err);
    process.exit();
});

fork1.js

process.argv.forEach(function (item) {
    process.stdout.write(item + '\r\n');
});

fork2.js

let fs = require('fs');
let out = fs.createWriteStream(path.join(__dirname, 'msg.txt'));
process.on('message', function (data) {
    out.write(data);
});

2.2.3 子进程与父进程共享HTTP服务器 #

let http = require('http');
let {
    fork
} = require('child_process');
let fs = require('fs');
let net = require('net');
let path = require('path');
let child = fork(path.join(__dirname, '8.child.js'));
let server = net.createServer();
server.listen(8080, '127.0.0.1', function () {
    child.send('server', server);
    console.log('父进程中的服务器已经创建');
    let httpServer = http.createServer();
    httpServer.on('request', function (req, res) {
        if (req.url != '/favicon.ico') {
            let sum = 0;
            for (let i = 0; i < 100000; i++) {
                sum += 1;
            }
            res.write('客户端请求在父进程中被处理。');
            res.end('sum=' + sum);
        }
    });
    httpServer.listen(server);
});
let http = require('http');
process.on('message', function (msg, server) {
    if (msg == 'server') {
        console.log('子进程中的服务器已经被创建');
        let httpServer = http.createServer();
        httpServer.on('request', function (req, res) {
            if (req.url != '/favicon.ico') {
                sum = 0;
                for (let i = 0; i < 10000; i++) {
                    sum += i;
                }
                res.write('客户端请求在子进程中被处理');
                res.end('sum=' + sum);
            }
        });
        httpServer.listen(server);
    }
});
let http = require('http');
let options = {
    hostname: 'localhost',
    port: 8080,
    path: '/',
    method: 'GET'
}
for (let i = 0; i < 10; i++) {
    let req = http.request(options, function (res) {
        res.on('data', function (chunk) {
            console.log('响应内容:' + chunk);
        });
    });
    req.end();
}

2.2.4 子进程与父进程共享socket对象 #

let {
    fork
} = require('child_process');
let path = require('path');
let child = fork(path.join(__dirname, '11.socket.js'));
let server = require('net').createServer();
server.on('connection', function (socket) {
    if (Date.now() % 2 == 0) {
        child.send('socket', socket);
    } else {
        socket.end('客户端请求被父进程处理!');
    }
});
server.listen(41234, );
process.on('message', function (m, socket) {
    if (m === 'socket') {
        socket.end('客户端请求被子进程处理.');
    }
});
let net = require('net');
let client = new net.Socket();
client.setEncoding('utf8');
client.connect(41234, 'localhost');
client.on('data', function (data) {
    console.log(data);
});

2.3 exec开启子进程 #

child_process.exec(command,[options],[callback]);
let {
    exec
} = require('child_process');
let path = require('path');
let p1 = exec('node test1.js a b c', {
    cwd: path.join(__dirname, 'test3')
}, function (err, stdout, stderr) {
    if (err) {
        console.log('子进程开启失败:' + err);
        process.exit();
    } else {
        console.log('子进程标准输出\r\n' + stdout.toString());
        p2.stdin.write(stdout.toString());
    }
});
let p2 = exec('node test2.js', {
    cwd: path.join(__dirname, 'test3')
}, function (err, stdout, stderr) {
    process.exit();
});
let path = require('path');
process.argv.forEach(function (item) {
    process.stdout.write(item + '\r\n');
});
let fs = require('fs');
let path = require('path');
let out = fs.createWriteStream(path.join(__dirname, 'msg.txt'));
process.stdin.on('data', function (data) {
    out.write(data);
    process.exit();
})

2.4 execFile开启子进程 #

child_process.execFile(file,[args],[optioins],[callback]);
let {
    execFile
} = require('child_process');
let path = require('path');

let p1 = execFile('node', ['./test1.js'], {
    cwd: path.join(__dirname, 'test4')
}, function (err, stdout, stderr) {
    if (err) {
        console.log('子进程1开启失败:' + err);
        process.exit();
    } else {
        console.log('子进程标准输出:' + stdout.toString());
        p2.stdin.write(stdout.toString());
    }
});
let p2 = execFile('node', ['./test2.js'], {
    cwd: path.join(__dirname, 'test4')
}, function (err, stdout, stderr) {
    if (err) {
        console.log('子进程2开启失败:' + err);
        process.exit();
    } else {
        console.log('子进程标准输出:' + stdout.toString());
    }
});
#!/usr/bin/env node

let path = require('path');
process.argv.forEach(function (item) {
    process.stdout.write(item + '\r\n');
});
#!/usr/bin/env node

let fs = require('fs');
let path = require('path');
let out = fs.createWriteStream(path.join(__dirname, 'msg.txt'));
process.stdin.on('data', function (data) {
    out.write(data);
    process.exit();
})

3. cluster #

为了利用多核CPU的优势,Node.js提供了一个cluster模块允许在多个子进程中运行不同的Node.js应用程序。

3.1 fork方法创建work对象 #

3.1.1 获取所有的worker #

for(let index in cluster.workers){
    console.log(cluster.workers[index]);
}

3.1.2 获取当前的worker和id #

if(cluster.isMaster){
  cluster.fork()
}else if(cluster.isWorker){
  console.log('I am worker #'+cluster.worker.id);
}

3.1.3 服务器 #

let cluster = require('cluster');
let http = require('http');
if (cluster.isMaster) {
    cluster.fork();
    console.log('这段代码运行在主进程里');
} else {
    http.createServer(function (req, res) {
        if (req.url != '/favicon.ico') {
            res.end('hello');
            console.log('这段代码运行在子进程里');
        }
    }).listen(8080);
}

3.1.4 fork事件 #

当使用fork方法开启子进程时,将同时触发fork事件

cluster.on('fork',function(worker){
  console.log('子进程 '+workder.id+'被开启');  
});

3.1.5 online事件 #

cluster.on('online',function(worker){
  console.log('已经收到子进程#'+workder.id+"的消息");
});

3.1.6 listening #

当在子进程运行的Node.js应用程序中调用服务器的listen方法后,该服务器开始对指定地址及端口进行监听,同时触发listening事件。

let cluster = require('cluster');
let http = require('http');
if (cluster.isMaster) {
    cluster.fork();
    console.log('这段代码运行在主进程里');
} else {
    http.createServer(function (req, res) {
        if (req.url != '/favicon.ico') {
            res.end('hello');
            console.log('这段代码运行在子进程里');
        }
    }).listen(8080, 'localhost');
}
cluster.on('online', function (worker) {
    console.log('已经收到子进程#' + worker.id + "的消息");
});
cluster.on('listening', function (worker, address) {
    console.log('子进程中的服务器开始监听,地址为:' + address.address + ":" + address.port);
});

3.1.7 setupMaster #

子进程中的Node.js应用程序默认运行当前正在运行的Node.js应用程序中的主模块文件。可以使用setupMaster方法修改子进程中运行的模块文件

cluster.setupMaster([settings]);
let cluster = require('cluster');
cluster.setupMaster({
    exec: 'subtask.js'
});
cluster.fork();
console.log('这段代码被运行子主进程中');
console.log('cluster.settings属性值: %j', cluster.settings);
let http = require('http');
http.createServer(function (req, res) {
    if (req.url != '/favicon.ico') {
        res.writeHead(200);
        res.end('ok');
        console.log('这段代码被运行在子进程中');
    }
}).listen(8080);

3.1.8 在子进程里运行服务器 #

当在子进程里运行服务器时,客户端总是先被主进程接收,然后转发给子进程中的服务器。如果在多个子进程中运行服务器,当主进程接收到客户端请求后,将会自动分配给一个当前处于空闲状态的子进程。

let cluster = require('cluster');
let http = require('http');
if (cluster.isMaster) {
    cluster.fork();
    cluster.fork();
} else {
    http.createServer(function (req, res) {
        if (req.url !== '/favicon.ico') {
            let sum = 0;
            for (let i = 0; i < 1000000; i++) {
                sum += i;
            }
            res.writeHead(200);
            res.write(`客户端请求在子进程${cluster.worker.id}中被处理`);
            res.end(`子进程${cluster.worker.id}中的计算结果=${sum}`);
        }
    }).listen(8080);
}

3.1.9 在子进程使用单独的输出 #

let cluster = require('cluster');
let http = require('http');
if (cluster.isMaster) {
    cluster.setupMaster({
        silent: true
    });
    let worker = cluster.fork();
    worker.process.stdout.on('data', function (data) {
        console.log('接收到来自客户端的请求,目标地址:' + data);
    });
} else {
    http.createServer(function (req, res) {
        if (req.url !== '/favicon.ico') {
            let sum = 0;
            for (let i = 0; i < 1000000; i++) {
                sum += i;
            }
            res.writeHead(200);
            console.log(`客户端请求在子进程${cluster.worker.id}中被处理`);
            res.write(`客户端请求在子进程${cluster.worker.id}中被处理`);
            res.end(`子进程${cluster.worker.id}中的计算结果=${sum}`);
        }
    }).listen(8080);
}

3.2 worker对象 #

3.2.1 online #

当新建一个工作进程后,工作进程应当响应一个online消息给主进程。当主进程收到online消息后触发这个事件

let cluster = require('cluster');
let http = require('http');
if (cluster.isMaster) {
    let worker = cluster.fork();
    console.log('这段代码被运行在主进程里');
    worker.on('online', function () {
        console.log(`已经收到子进程${worker.id}的运行信息`);
    });
} else {
    http.createServer(function (req, res) {
        if (req.url !== '/favicon.ico') {
            let sum = 0;
            for (let i = 0; i < 1000000; i++) {
                sum += i;
            }
            res.end('ok');
            console.log(`这段代码被运行在子进程中。`);
        }
    }).listen(8080);
}

3.2.2 send #

在使用fork发放开启子进程后,可以使用fork方法所返回的worker对象的send方法在主进程中向子进程发送消息。

worker.send(message,[sendHandle]);//在主进程中向子进程发送消息
process.send(message,[sendHandle]);//在子进程中像主进程发送消息
process.on('message',function(m,setHandle){});
let cluster = require('cluster');
cluster.setupMaster({
    exec: 'child.js'
});
let worker = cluster.fork();
worker.on('message', function (m) {
    console.log('父进程接收到消息:', m);
    process.exit();
});
worker.send({
    name: 'zfpx'
});

3.2.3 共享socket #

let http = require('http');
let cluster = require('cluster');
let net = require('net');
cluster.setupMaster({
    exec: '22.subsocket.js'
});
let worker = cluster.fork();
let server = require('net').createServer();
server.on('connection', function (socket) {
    if (Date.now() % 2 == 0) {
        worker.send('socket', socket);
    } else {
        socket.end('客户端的请求在主进程中处理');
    }

});
server.listen(41234, 'localhost');
worker.on('message', function (m, socket) {
    console.log(m);

});
process.on('message', function (msg, socket) {
    if (msg == 'socket') {
        socket.end('子进程中返回消息:' + msg);
        process.send('告诉父进程我处理了一个消息');
    }
});

3.2.4 kill #

当使用fork方法开启子进程后,可以使用fork方法返回的worker对象的kill方法强制关闭子进程

worker.kill([signal]);

3.2.5 exit #

当子进程退出时,将会触发worker对象的exit事件

worker.on('exit',function(code,signal));
let cluster = require('cluster');
let http = require('http');
if (cluster.isMaster) {
    cluster.setupMaster({
        silent: true
    });
    let worker = cluster.fork();
    worker.process.stdout.on('data', function (data) {
        console.log('接收到来自客户端的请求,目标地址为:' + data);
        worker.kill(); //让子进程退出
    });
    worker.on('exit', function (code, signal) {
        console.log(arguments)
        //suicide可以判断是自动退出还是异常退出,退出之前时undefined.自动退出为true,异常退出为false
        if (worker.exitedAfterDisconnect  == true) {
            console.log(`子进程%{worker.id}自动退出`);
        } else if (worker.exitedAfterDisconnect  == false) {
            console.log(`子进程${worker.id}异常退出,退出代码为${code}`);
        }
        if (signal) {
            console.log('退出信号为 %s', signal);
        }
    });
} else {
    let server = http.createServer(function (req, res) {
        if (req.url != '/favicon.ico') {
            res.end('hello');
            process.stdout.write(req.url);
        }
    }).listen(8080);
}

3.2.6 disconnect #

可以使用worker对象的disconnect方法使该子进程不再接收外部连接

let cluster = require('cluster');
let http = require('http');
if (cluster.isMaster) {
    cluster.setupMaster({ silent: true });
    let worker = cluster.fork();
    worker.process.stdout.on('data', function (data) {
        console.log('接收到来自客户端的请求,目标地址为:' + data);
        setTimeout(function () {
            worker.disconnect();//不再接收连接
            worker.send('disconnect');
        }, 2000);
    });

    worker.on('disconnect', function () {
        console.log(`子进程${worker.id}断开连接`);
    });
    worker.on('exit', function (code, signal) {
        if (worker.exitedAfterDisconnect) {
            console.log(`子进程${worker.id}正常退出`);
        } else {
            console.log(`子进程${worker.id}异常退出`);
        }
        if (signal) {
            console.log(' 退出信号为' + signal);
        }
    });

} else {
    let http = require('http');
    let server = http.createServer(function (req, res) {
        if (req.url != '/favicon.ico') {
            res.end('hello');
            process.stdout.write(req.url);
        }
    }).listen(8080);
    process.on('message', function (msg) {
        if (msg == 'disconnect') {
            //process.exit(0);
        }

    });
}