卜娃娃|nodejs 的融会贯通,你学会了吗?( 四 )

fork

  • fork 方法会开发一个 IPC 通道 , 不同的 Node 进程进行消息传送
  • 一个子进程消耗 30ms 启动时间和 10MB 内存
  • 子进程:`process.on('message')`、`process.send()`
  • 父进程:`child.on('message')`、`child.send()`
父子通信// parent.jsconst cp = require('child_process');const child = cp.fork('./child', {silent: true});child.send('monkeys');child.on('message', function (message) {console.log('got message from child', message, typeof message);})child.stdout.pipe(process.stdout);setTimeout(function () {child.disconnect();}, 3000);// child.jsprocess.on('message', function (message) {console.log('got one', message);process.send('no pizza');process.send(1);process.send({my: 'object'});process.send(false);process.send(null);});console.log(process);复制代码常用技巧退出时杀死所有子进程保留对由 spawn 返回的 ChildProcess 对象的引用 , 并在退出主进程时将其杀死
const spawn = require('child_process').spawn;const children = [];process.on('exit', function () {console.log('killing', children.length, 'child processes');children.forEach(function (child) {child.kill();});});children.push(spawn('/bin/sleep', ['10']));children.push(spawn('/bin/sleep', ['10']));children.push(spawn('/bin/sleep', ['10']));setTimeout(function () {process.exit(0);}, 3000);复制代码Cluster 的理解
  • 解决 NodeJS 单进程无法充分利用多核 CPU 问题
  • 通过 master-cluster 模式可以使得应用更加健壮
  • Cluster 底层是 child_process 模块 , 除了可以发送普通消息 , 还可以发送底层对象 TCP、UDP 等
  • TCP 主进程发送到子进程 , 子进程能根据消息重建出 TCP 连接 , Cluster 可以决定 fork 出合适的硬件资源的子进程数
Node 多线程单线程问题
  • 对 cpu 利用不足
  • 某个未捕获的异常可能会导致整个程序的退出
Node 线程
  • Node 进程占用了 7 个线程
  • Node 中最核心的是 v8 引擎 , 在 Node 启动后 , 会创建 v8 的实例 , 这个实例是多线程的
  • 主线程:编译、执行代码
  • 编译/优化线程:在主线程执行的时候 , 可以优化代码
  • 分析器线程:记录分析代码运行时间 , 为 Crankshaft 优化代码执行提供依据
  • 垃圾回收的几个线程
  • JavaScript 的执行是单线程的 , 但 Javascript 的宿主环境 , 无论是 Node 还是浏览器都是多线程的
异步 IO
  • Node 中有一些 IO 操作(DNS , FS)和一些 CPU 密集计算(Zlib , Crypto)会启用 Node 的线程池
  • 线程池默认大小为 4 , 可以手动更改线程池默认大小 process.env.UV_THREADPOOL_SIZE = 64
cluster 多进程const cluster = require('cluster');const http = require('http');const numCPUs = require('os').cpus().length;if (cluster.isMaster) {console.log(`主进程 ${process.pid} 正在运行`);for (let i = 0; i < numCPUs; i++) {cluster.fork();}cluster.on('exit', (worker, code, signal) => {console.log(`工作进程 ${worker.process.pid} 已退出`);});} else {// 工作进程可以共享任何 TCP 连接 。// 在本例子中 , 共享的是 HTTP 服务器 。http.createServer((req, res) => {res.writeHead(200);res.end('Hello World');}).listen(8000);console.log(`工作进程 ${process.pid} 已启动`);}复制代码