-
什么是进程
-
场景 -
notepad.exe是一个程序,不是进程 -
双击notepad.exe时,操作系统会开启一个进程 -
定义 -
进程是程序的执行实例 -
程序在CPU上执行时的活动叫做进程 -
实际上并没有明确的定义,只有一些规则 -
特点 -
一个进程可以创建另一个进程(父进程与子进程) -
通过任务管理器可以看到进程
-
了解CPU
-
特点 -
一个单核CPU,在一个时刻,只能做一件事情 -
那么如何让用户同时看电影、听声音、写代码呢? -
答案是在不同进程中快速切换 -
多程序并发执行 -
指多个程序在宏观上并行,微观上串行 -
每个进程会出现「执行-暂停-执行」的规律 -
多个进程之间会出现抢资源(如打印机被占用)的现象
-
进程的两个状态
-
非运行和运行状态的切换

-
进程队列分派cpu的过程

-
什么事进程阻塞
-
等待执行的进程中都是非运行态 -
某一些(A)在等待CPU资源另一些(B)在等待I/O完成(如文件读取) -
如果这个时候把CPU分配给B进程,B还是在等I/O -
我们把这个B叫做阻塞进程,因此,分派程序只会把CPU分配给非阻塞进程 -
了解阻塞的概念之后,进程的状态就会多一个阻塞态,非运行变成就绪和阻塞两种

-
线程Thread的引入
-
线程的引入,分为以下两个阶段 -
在面向进程设计的系统中,进程是程序的基本执行实体 -
在面向线程设计的系统中,进程本身不是基本运行单位,而是线程的容器 -
引入原因 -
进程是执行的基本实体,也是资源分配的基本实体 -
导致进程的创建、切换、销毁太消耗CPU时间了,于是引入线程,线程作为执行的基本实体 -
而进程只作为资源分配的基本实体,此处可以以设计师和工程师分开招聘举例
-
线程Thread的概念
-
基础概念 -
CPU调度和执行的最小单元 -
一个进程中至少有一个线程,可以有多个线程 -
一个进程中的线程共享该进程的所有资源 -
进程的第一个线程叫做初始化线程 -
线程的调度可以由操作系统负责,也可以用户自己负责 -
举例 -
浏览器进程里面有渲染引擎、V8引擎、存储模块、网络模块、用户界面模块等 -
每个模块都可以放在一个线程里
-
node-js的child_process之exec的使用
-
使用目的 -
子进程的运行结果储存在系统缓存之中(最大200Kb) -
等到子进程运行结束以后,主进程再用回调函数读取子进程的运行结果 -
这段代码是使用Node.js中的child_process模块来执行操作系统的命令。 -
具体来说,它执行了一个ls命令,该命令用于列出指定目录中的文件和子目录。
const child_process = require('child_process')
const {exec} = child_process
exec('ls ../', (error, stdout, stderr)=>{
console.log(error)
console.log(stdout)
console.log(stderr)
})
-
可以改成流的形式
const { exec } = require('child_process');
// 使用 exec 方法创建子进程
const child = exec('ls ../');
// 处理标准输出
child.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
// 处理标准错误输出
child.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
// 处理子进程关闭事件
child.on('close', (code) => {
console.log(`子进程退出,退出码 ${code}`);
});
-
我们也可以用Node.js的util.promisify来将exec方法转换为返回Promise的形式
const child_process = require('child_process')
const util = require("util")
const {exec} = child_process
const exec2 = util.promisify(exec)
exec2('ls ../').then(data=>{
console.log(data.stdout)
})
-
exec的风险
-
exec有风险可能会被注入,执行意外的代码。下面代码中如果用户输入包含恶意代码,可能导致不安全的命令执行。
const child_process = require('child_process')
const util = require("util")
const {exec} = child_process
const exec2 = util.promisify(exec)
const userInput = '. && pwd'
exec2(`ls ${userInput}`).then(data=>{
console.log(data.stdout)
})
-
避免风险exec的风险使用execFile
-
因为它传递的参数是数组,避免了直接字符串拼接。
const child_process = require('child_process')
const util = require("util")
const {execFile} = child_process
const userInput = ".";
execFile("ls", ["-la", userInput], (error, stdout) => {
console.log(error)
console.log(stdout)
})
-
execFile支持流,可以改写成流的形式
const userInput = ".";
const streams = execFile("ls", ["-la", userInput])
streams.stdout.on('data', (chunk)=> {
console.log(chunk)
})
-
execFile的options参数 -
cwd-Current working directory -
env-环境变量 -
shell-用什么shell -
maxBuffer-最大缓存,默认1024*1024字节
execFile("ls", ["-la", userInput], {
cwd: '/',
env: {
NODE_ENV: 'development'
},
shell: 'bash',
maxBuffer: 1024 * 1024
}, (error, stdout) => {
console.log(error)
console.log(stdout)
})
-
第三个Api,spawn
-
中文意思是产卵 -
用法与execFile方法类似 -
没有回调函数,只能通过流事件获取结果 -
没有最大200Kb的限制(因为是流) -
经验 -
能用spawn的时候就不要用execFile,速度快也没有缓存大小限制
const userInput = ".";
const streams = spawn("ls", ["-la", userInput], {
cwd: '/',
env: {
NODE_ENV: 'development'
},
})
streams.stdout.on('data', (chunk)=> {
console.log(chunk.toString())
})
-
第四个api,fork
-
作用 -
创建一个子进程,执行Node脚本 -
fork(‘./child.js’)相当于spawn(‘node’,[‘./child.js’]) -
特点 -
会多出一个message事件,用于父子通信 -
会多出一个send方法 -
例子 -
新建n.js和child.js -
n.js
const child_process = require('child_process')
let n = child_process.fork('./child.js');
n.on('message', function (m) {
console.log('父进程得到值:', m);
});
-
child.js
setTimeout(()=>{
process.send({foo: 'bar'});
},2000)
-
可以得到如下结果

-
总结: -
fork像是spawn的语法糖,但是经常只用fork
-
子线程的使用
-
worker threads -
API列表 -
isMainThread -
new Worker(filename) -
parentPort -
postMessage -
事件列表 -
message -
exit -
例子
const {Worker, isMainThread, parentPort} = require('worker_threads');
if (isMainThread) {
const worker = new Worker(__filename);
worker.once('message', (message) => {
console.log('father', message);
});
worker.postMessage('Hello,world!');
} else {
parentPort.once('message', (message) => {
console.log('son start')
parentPort.postMessage(message);
console.log('son done')
});
}

原文始发于微信公众号(前端之乐):深入浅出:理解进程、线程与Node.js子进程的完整指南
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/274556.html