node进程process的属性和事件

80 阅读5分钟

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