1。回顾进程和线程的定义进程(Process)是计算机中运行在一定数据集上的程序,是系统资源分配和调度的基本单位。线程(Thread)是操作系统能够进行操作调度的最小单元。它包含在流程中,是流程中的实际操作单元。2、Node.js的单线程Node特点主线程是单线程的。一个进程只开一个主线程。基于事件驱动,异步非阻塞I/O,可应用于高并发场景。Nodejs中没有多线程。为了充分利用多核CPU,可以使用子进程来实现内核负载均衡。那么我们需要解决以下问题:Node.js在做耗时计算时会阻塞。Node.js如何启用多进程。如何在开发过程中实现进程守护进程。3.场景实例consthttp=require('http');http.createServer((req,res)=>{if(req.url==='/sum'){//summingletsum=0;for(leti=0;i<10000000000;i++){sum+=i;}res.end(sum+'')}else{res.end('end');}}).listen(3000);//这里先访问/sum,当你创建一个新的浏览器页卡访问///时,你会发现必须等待/sum路径被处理后才能处理/path4.启动进程Node.js进程创建是通过child_process模块:child_process.spawn()异步生成子进程。child_process.fork()生成一个新的Node.js进程并使用已建立的IPC通信通道调用指定的模块,这允许在父进程和子进程之间发送消息。child_process.exec()生成一个shell并在该shell中运行命令。child_process.execFile()不需要生成shell。4.1.spawnspawnspawn,可以通过这个方法创建子进程:let{spawn}=require("child_process");letpath=require("path");//通过node命令执行sub_process.js文件letchildProcess=spawn("node",['sub_process.js'],{cwd:path.resolve(__dirname,"test"),//找到文件的目录是stdio:[0,1,2]});//监控errorschildProcess.on("error",function(err){console.log(err);});//监听关闭事件childProcess.on("close",function(){console.log("close");});//监听退出事件childProcess.on("exit",function(){console.log("exit");});stido的这个属性很有特色,这里我们给0,1,2三个值分别对应进程的process.stdin,process.stdout和process.stderr,表示主进程和子进程共享标准输入输出:letchildProcess=spawn("node",['sub_process.js'],{cwd:path.resolve(__dirname,"test"),//找到文件的目录是test目录下的stdio:[0,1,2]});可以打印当前进程下sub_process.js的执行结果。默认情况下,不提供stdio参数为stdio:['pipe'],即进程之间的通信只能通过流实现:let{spawn}=require("child_process");letpath=require("path");//通过node命令执行sub_process.js文件letchildprocess=spawn("node",['sub_process.js'],{cwd:path.resolve(__dirname,"test"),stdio:['pipe']//通过流});//子进程读取和writedatachildProcess.stdout.on('data',function(data){console.log(data);});//子进程写入标准输出process.stdout.write('hello');使用ipc通信,设置值为stdio:['pipe','pipe','pipe','ipc']可以通过on('message')通信,发送:let{spawn}=require("child_process");letpath=require("path");//通过node命令执行sub_process.js文件letchildProcess=spawn("node",['sub_process.js'],{cwd:path.resolve(__dirname,"test"),stdio:['pipe','pipe','pipe','ipc']//传流的方式});//监听消息childProcess.on('message',function(data){console.log(data);});//发送消息process.send('hello');也可以传入ignore表示忽略,传入inherit表示默认共享父进程的标准输入输出创建独立进程:let{spawn}=require("child_process");letpath=require("path");//通过node命令执行sub_process.js文件letchild=spawn('node',['sub_process.js'],{cwd:path.resolve(__dirname,'test'),stdio:'ignore',detached:true//独立线程});child.unref();//放弃控制4.2.forkspawnanewprocess,默认可以通过ipc进行通信:let{fork}=require("child_process");letpath=require("path");//通过node命令执行sub_process.js文件letchildProcess=fork('sub_process.js',{cwd:path.resolve(__dirname,"test"),});childProcess.on('message',function(data){console.log(data);});fork是基于spawn的,可以通过传入more一个silent属性来设置是否共享输入输出。fork原理:functionfork(filename,options){letstdio=['inherit','inherit','inherit']if(options.silent){//如果是quiet,忽略子进程的输入输出stdio=['ignore','ignore','ignore']}stdio.push('ipc');//默认支持ipc的方式options.stdio=stdioreturnspawn('node',[filename],options)}这里我们可以解决“3.场景实例”中的场景实例:consthttp=require('http');const{fork}=require('child_process');constpath=require('path');http.createServer((req,res)=>{if(req.url==='/sum'){letchildProcess=fork('calc.js',{cwd:path.resolve(__dirname,'test')});childProcess.on('message',function(data){res.end(data+'');})}else{res.end('ok');}}).listen(3000);4.3.execFile直接执行某个A文件:letchildProcess=execFile("node",['./test/sub_process'],function(err,stdout,stdin){console.log(stdout);});spawn方法在内部调用。4.4.execletchildProcess=exec("node'./test/sub_process'",function(err,stdout,stdin){console.log(stdout)});内部调用的是execFile,其实以上三个方法都是基于spawn的。5.clusterNode.js的单个实例在单个线程中运行。为了利用多核系统,用户有时会希望启动Node.js进程集群来处理负载。通过流程自己实现集群。子进程与父进程共享HTTP服务器fork实现:lethttp=require('http');let{fork}=require('child_process');letfs=require('fs');letnet=require('net');letpath=require('path');letchild=fork(path.join(__dirname,'8.child.js'));letserver=net.createServer();server.listen(8080,'127.0.0.1',函数(){child.send('server',server);console.log('父进程中的server已创建');lethttpServer=http.createServer();httpServer.on('request',function(req,res){if(req.url!='/favicon.ico'){letsum=0;for(leti=0;i<100000;i++){sum+=1;}res.write('客户端请求是在父进程中被处理。');res.end('sum='+sum);}});httpServer.listen(server);});lethttp=require('http');process.on('message',function(msg,server){if(msg=='server'){console.log('子进程中的server已经创建');lethttpServer=http.createServer();httpServer.on('request',function(req,res){if(req.url!='/favicon.ico'){sum=0;for(leti=0;i<10000;i++){sum+=i;}res.write('客户端请求在子进程处理于');res.end('sum='+sum);}});httpServer.listen(server);}});进程与父进程共享socket对象:let{fork}=require('child_process');letpath=require('path');letchild=fork(path.join(__dirname,'11.socket.js'));letserver=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('客户端请求为子进程处理');}});使用集群模块更方便:letcluster=require("cluster");lethttp=require("http");letcpus=require("os").cpus()。
