process全局对象进程
const process = require('process')
属性
const process = require("process");
// node版本
/**
* v12.22.0
*/
console.log(process.version);
// 更多依赖的版本
/**
{
node: '12.22.0',
v8: '7.8.279.23-node.46',
uv: '1.40.0',
zlib: '1.2.11',
brotli: '1.0.9',
ares: '1.16.1',
modules: '72',
nghttp2: '1.41.0',
napi: '8',
llhttp: '2.1.3',
http_parser: '2.9.4',
openssl: '1.1.1j',
cldr: '37.0',
icu: '67.1',
tz: '2019c',
unicode: '13.0'
}
*/
console.log(process.versions);
// 平台
/**
* win32
*/
console.log(process.platform);
// node地址
/**
* C:\Program Files\nodejs\node.exe
*/
console.log(process.execPath);
/** 配置信息
* {
target_defaults: {
cflags: [],
default_configuration: 'Release',
defines: [],
include_dirs: [],
libraries: []
},
variables: {
asan: 0,
build_v8_with_gn: false,
coverage: false,
dcheck_always_on: 0,
debug_nghttp2: false,
debug_node: false,
enable_lto: false,
enable_pgo_generate: false,
enable_pgo_use: false,
force_dynamic_crt: 0,
host_arch: 'x64',
icu_data_in: '..\\..\\deps/icu-small\\source/data/in\\icudt67l.dat',
icu_default_data: '',
icu_endianness: 'l',
icu_gyp_path: 'tools/icu/icu-generic.gyp',
icu_locales: 'en,root',
icu_path: 'deps/icu-small',
icu_small: true,
icu_ver_major: '67',
is_debug: 0,
napi_build_version: '8',
nasm_version: '2.14',
node_byteorder: 'little',
node_debug_lib: false,
node_enable_d8: false,
node_install_npm: true,
node_module_version: 72,
node_no_browser_globals: false,
node_prefix: '/usr/local',
node_release_urlbase: 'https://nodejs.org/download/release/',
node_shared: false,
node_shared_brotli: false,
node_shared_cares: false,
node_shared_http_parser: false,
node_shared_libuv: false,
node_shared_nghttp2: false,
node_shared_openssl: false,
node_shared_zlib: false,
node_tag: '',
node_target_type: 'executable',
node_use_bundled_v8: true,
node_use_dtrace: false,
node_use_etw: true,
node_use_node_code_cache: true,
node_use_node_snapshot: true,
node_use_openssl: true,
node_use_v8_platform: true,
node_with_ltcg: true,
node_without_node_options: false,
openssl_fips: '',
openssl_is_fips: false,
ossfuzz: false,
shlib_suffix: 'so.72',
target_arch: 'x64',
v8_enable_gdbjit: 0,
v8_enable_i18n_support: 1,
v8_enable_inspector: 1,
v8_enable_lite_mode: 0,
v8_enable_object_print: 1,
v8_no_strict_aliasing: 1,
v8_optimized_debug: 1,
v8_promise_internal_field_count: 1,
v8_random_seed: 0,
v8_trace_maps: 0,
v8_use_siphash: 1,
v8_use_snapshot: 1,
want_separate_host_toolset: 0
}
}
*/
console.log(process.config);
// 进程id,可以用supervisor看守nodejs进程,能重启nodejs
console.log(process.pid);
// 命令行标题 C:\Windows\system32\cmd.exe
console.log(process.title);
// 当前操作系统架构 x64
console.log(process.arch);
// 内存使用情况
/**
* {
rss: 21368832,// 进程占的总的消耗量
heapTotal: 5955584,// v8引擎分配的总的堆量
heapUsed: 3122312,// 已经使用的堆大小
external: 1083189,// 对外内存使用量,如buffer
arrayBuffers: 9386
}
*/
console.log(process.memoryUsage());
// 当前工作目录,current work directory
console.log(process.cwd());
// 修改当前工作目录
process.chdir("../");
console.log(process.cwd());
// 当前环境属性,环境变量
console.log(process.env);
// 进程执行时间
console.log(process.uptime());
事件
// 退出前事件
process.on("beforeExit", () => {
console.log("node before exit");
});
// 退出后事件
process.on("exit", () => {
console.log("node exited");
});
// 未捕获的异常
process.on("uncaughtException", (error) => {
console.log("uncaughtException", error);
});
// 捕获操作系统的中断信号
process.on("SIGINT", () => {
console.log("received singint info");
});
setTimeout(() => {
console.log("timeout"); // 进程不会停止,会等10s退出
}, 10000);
nextTick
nextTick执行时机顺序是,同步事件readFileSync - nextTick - 异步事件readFile
const fs = require("fs");
const myfn = function () {
console.log("call myfn");
};
process.nextTick(myfn);
console.log(fs.readFileSync("./app1.js").toString());
fs.readFile("./app.js", (error, data) => {
console.log(data.toString());
});
子进程child_process
因为nodejs是单线程即单进程的方式,适用于异步IO密集型应用,但是对于CPU计算密集型就不适合,因为如果主进程
阻塞将导致后续事件阻塞,对于CPU密集型,使用child_process开新进程,主进程可以开启很多子进程,子进程里面也可以开启子进程
,再通过相应事件方式,返回子进程执行结果给主进程,主子进程可以相互发消息。
有四种生成子进程的方式,第一种是spawn
方式,后续三种都是衍生之spawn
总结:
-
spawn 本质是最为基础的版本,其他三种方式fork,exec,execFile是衍生版本
-
spawn、fork 没有回调,exec、execFile 有回调
-
spawn 可以执行任何命令,linux的shell命令,windows的bash命令,node命令,最为通用的方式
-
fork 是spawn的具化,只能是node进程的子进程,即只能是node子进程,不能是shell子进程等,实际fork应用更广泛
-
fork 可以通过 send,on 主子进程可以相互通信,通过ipc(Inter-Process Communication)的方式通信,创建子进程后,主子进程就会建立ipc连接,建立双向通信,通过主子进程发送消息监听消息
-
exec 和 execFile 可以任务是一回事,execFile只是对exec的第一个参数,命令和参数做了拆解开,exec和execFile都可以用,execFile会稍微效率高些
spawn
可以执行shell命令,也可以写node完整命令也就是shell命令,没有回调
const { spawn } = require("child_process");
// 使用shell命令,参数字符串数组,额外配置项,没有回调函数
const lsChildProcess = spawn("ls", ["-al", "./"]);// spawn("node", ["./app2.js"]);
lsChildProcess.stdout.on("data", (data) => {
console.log(data.toString());
console.log("child process id", lsChildProcess.pid);
});
lsChildProcess.on("exit", (code, signal) => {
console.log("退出码", code);
});
fork
fork实际是spawn的一种特例,只能由node的主进程产生node的子进程,只能是node命令,没有回调
主子进程可以相互发消息,发送消息用send,相应消息用on
// fork实际是spawn的一种特例,只能由node的主进程产生node的子进程,只能是node命令
const { fork } = require("child_process");
// 只能是node命令,第一个参数是node模块,参数字符串数组,额外配置项,没有回调函数
const childProcess = fork("./app6");// fork("./app6.js", { silent: true }) silent 只打印主进程console
childProcess.on("message", (message) => {
console.log(message);
});
childProcess.send("hello");
子进程app6.js
process.on("message", (message) => {
console.log(message);
process.send("welcome");
});
exec
可以执行shell命令,也可以写node完整命令也就是shell命令,有回调
// exec执行shell,有回调
const { exec } = require("child_process");
// 只能是node命令,第一个参数是node模块,参数字符串数组,额外配置项,没有回调函数
const childProcess = exec("node ./app6.js", (error, stdout, stderr) => {
if (error) {
console.log(error);
throw error;
} else {
console.log(stdout.toString());
}
});
子进程app6.js
["htllo", "world"].forEach((w) => {
console.log(w);
});
execFile
exec会开启新的shell窗口,execFile不会开启新shell窗口,有回调
,可以通过参数 shell: false 默认不开启改变
// execFile是exec的一种具化特例
// exec会开启新的shell窗口,execFile不会开启新shell窗口
const { execFile } = require("child_process");
execFile("node", ["./app6.js"], { shell: false }, (error, stdout, stderr) => {
if (error) {
console.log(error);
throw error;
} else {
console.log(stdout.toString());
}
});
cluster
对子进程集群完美封装,建立多个子进程集群管理,利用子进程协同工作,充分利用多核能力
下面代码放到linux上执行比较好,window看不出不同请求是不同worker在处理
会开启多个子进程监听3000端口,实际上只有主进程监听3000端口号,主子进程使用的是socket建立的双向通信
const cluster = require("cluster");
const http = require("http");
const os = require("os");
const cpuCount = os.cpus().length;
// console.log(cpuCount); // 电脑物理上只有4个核,因为操作系统都会使用超线程技术,每个会多出来一份核,这里就是8
// 主进程 isMaster 判断
if (cluster.isMaster) {
cluster.schedulingPolicy = cluster.SCHED_NONE;
for (let i = 0; i < cpuCount; i++) {
cluster.fork(); // fork后,会重新执行当前js脚本
}
cluster.on("exit", (worker, code, signal) => {
console.log(worker, process.pid);
});
} else {
// 子进程
const httpServer = http.createServer((request, response) => {
let data = "";
request.on("data", (chunk) => {
data += chunk;
});
request.on("end", () => {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end(`${process.pid}`); // 哪个子进程在执行,就显示哪个子进程id
});
});
httpServer.listen(3000, () => {
console.log(process.pid + " listen port 3000");
});
}
测试shell
#!/bin/bash'
for i in $(seq 1 200)
do
curl 'http://localhost:3000'
echo
sleep 0.3
done