zoukankan      html  css  js  c++  java
  • node.js中process进程的概念和child_process子进程模块的使用

    进程,你可以把它理解成一个正在运行的程序。node.js中每个应用程序都是进程类的实例对象。

    node.js中有一个 process 全局对象,通过它我们可以获取,运行该程序的用户,环境变量等信息。

    一、process 对象

    console.log('可执行文件绝对路径', process.execPath);
    console.log('版本号', process.version);
    console.log('依赖库的版本号', process.versions);
    console.log('运行平台', process.platform);
    console.log('标准输入流', process.stdin);
    console.log('标准输出流', process.stdout);
    console.log('标准错误流', process.stderr);
    console.log('命令行参数数组', process.argv);
    console.log('系统环境变量', process.env);
    console.log('进程ID', process.pid);
    console.log('标题', process.title);
    console.log('处理器架构', process.arch);
    

    通过 memoryUsage() 查看内存使用量:

    console.log(process.memoryUsage());
    

    rss 表示进程占用的内存,包括堆,栈,代码段。

    heapTotal 表示堆占用的内存。

    heapUsed 表示堆使用的部分。

    external 表示外部使用的部分,C++对象占用的。

    对象,字符串,闭包存放于堆内存,变量存放于栈内存,js源代码存放于代码段。

    console.log(process.memoryUsage());
    let buf = Buffer.alloc(1024 * 1024 * 1024);
    console.log(process.memoryUsage());
    

    当我们通过Buffer创建一个足够大的变量时,这时只能借助于外部内存,使用C++去完成。node.js能够使用的内存上限是1.7G。

    使用 chdir() 修改程序当前的工作目录,通过 cwd() 获取当前工作目录。

    console.log(process.cwd());
    //修改程序当前的工作目录
    process.chdir('../');
    console.log(process.cwd());
    

    通过 exit() 来结束进程

    process.exit(0);

    调用 exit() 结束进程时,会触发 'exit' 事件。

    process.on('exit', function () {
        console.log('程序退出了');
    });
    process.exit(0);

    通过 kill() 给指定进程发送信号

    SIGINT 程序终止信号,当用户按下ctrl+c时发出,将通知进程终止。

    SIGTERM 程序结束信号,通知程序正常退出,kill()方法默认就是这个信号。

    process.kill(process.pid, 'SIGINT');
    

    通过 uptime() 返回程序运行的时间

    console.log(process.uptime());
    

    通过 hrtime() 计算代码段运行时间,hrtime() 返回一个数组,第一个表示秒,第二个表示纳秒

    let start = process.hrtime();
    let sum = 0;
    for (i = 0; i < 1000000000; i++) {
        sum += i;
    }
    let end = process.hrtime(start);
    console.log('耗时 : ', end[0], '秒');
    

    当程序抛出一个没有被捕获的异常时,触发 'uncaughtException' 事件。

    process.on('uncaughtException', function (err) {
        console.log('捕获了一个未被处理的异常');
        console.log(err);
    });
    //调用一个未定义的函数
    test();
    

    进程接收到一个信号时,会触发信号事件,我们可以监听到该事件。

    //让标准输入流处于流动模式,让程序无法退出
    process.stdin.resume();
    
    process.on('SIGINT', function () {
        console.log('程序退出');
        process.exit(0);
    });
    
    process.on('SIGTERM', function () {
        console.log('程序结束');
    });
    

      

    二、子进程模块child_process的使用

    我们都知道node.js是单线程的,如果某一个操作需要消耗大量资源和时间,会导致程序整体性能下降。

    我们可以创建子进程,让子进程去跑那些费时费力的操作,而主线程该干嘛干嘛。

    子进程间可以共享内存,通过互相通信来完成数据的交换。

    1、通过 spawn() 创建子进程

    const {spawn} = require('child_process');
    
    //参数一表示,要执行的命令
    //参数二表示,运行该命令的参数
    //参数三表示,创建子进程的配置
    let cp1 = spawn('node', ['1.js'], {
        //cwd表示当前子进程的工作目录
        cwd: process.cwd(),
        //子进程的环境变量
        env: process.env,
        //子进程的标准输入,标准输出,错误,的配置
        //pipe表示,父进程与子进程间建立管道,父进程可以访问子进程对应的输入,输出,和错误
        //ipc表示,父进程与子进程间建立一个专门用来传递消息的IPC通道,子进程调用send()方法向子进程发送消息,并触发'message'事件
        //ignore表示,忽略子进程的标准输入,标准输出,错误。
        //inherit表示,子进程共享父进程的标准输入,标准输出,错误。
        //stream表示,父进程与子进程共享一个流,比如文件流或socket。
        //正整数表示,父进程打开的文件描述符,与子进程共享,比如文件的fd。类似stream流对象共享。
        //null或undefined表示,父进程与子进程间创建管道
        stdio: ['pipe', process.stdout, 'pipe'],
        //子进程是否独立于父进程运行
        detached: false
    });
    

    1.js的代码:

    console.log('hello');
    

    运行代码后,我们可以看到子进程的 'hello',出现在了父进程的标准输出上。因为 stdio 的配置,我们让子进程与父进程共享标准输出。

    spawn() 会返回一个子进程对象,我们可以监听该对象的一些事件。

    const {spawn} = require('child_process');
    
    let cp1 = spawn('node', ['1.js'], {
        cwd: process.cwd(),
        env: process.env,
        stdio: ['pipe', process.stdout, 'pipe'],
        detached: false
    });
    
    //子进程所有输入/输出终止时,会触发子进程的 'close' 事件
    cp1.on('close', function (code, signal) {
        //当父进程关闭子进程时,signal表示父进程发送给子进程的信号名称
        console.log('子进程关闭了', code, signal);
    });
    
    //子进程退出时,会触发 'exit' 事件
    //注意,子进程退出,子进程的输入/输出有可能并未关闭。因为输入/输出有可能多个进程共享。
    cp1.on('exit', function (code, signal) {
        console.log('子进程退出', code, signal);
    });
    
    //子进程出错时,触发
    cp1.on('error', function (err) {
        console.log(err);
    });
    

    注意,stdio 设置成 pipe ,是把子进程的stdin,stdout,stderr导向了 spawn() 返回的子进程对象的stdin,stdout,stderr。

    然后父进程就可以通过子进程对象访问stdin,stdout,stderr。

    const {spawn} = require('child_process');
    
    let cp1 = spawn('node', ['1.js'], {
        cwd: process.cwd(),
        env: process.env,
        stdio: ['pipe', 'pipe', 'pipe'],
        detached: false
    });
    
    //监听子进程标准输入,输出,错误的数据。
    cp1.stdin.on('data', function (data) {
        console.log(data.toString());
    });
    cp1.stdout.on('data', function (data) {
        console.log(data.toString());
    });
    cp1.stderr.on('data', function (data) {
        console.log(data.toString());
    });
    

    1.js的代码:

    //往子进程标准输出中写入数据
    console.log('我是标准输出');
    //往子进程错误中写入数据
    console.error('我是一个错误');
    //往子进程标准输入中写入数据
    process.stdin.write('我是标准输入');
    

    当我们设置 stdio 为 ipc 时,会创建一个父进程与子进程传递消息的IPC通道。

    const {spawn} = require('child_process');
    
    let cp1 = spawn('node', ['1.js'], {
        cwd: process.cwd(),
        env: process.env,
        //注意这里,子进程只能有一个IPC通道
        stdio: ['pipe', 'ipc', 'pipe'],
        detached: false
    });
    
    //注意这里要用子进程对象进行监听
    //监听有没有消息
    cp1.on('message', function (data) {
        console.log('子进程发送的 : ', data.toString());
    });
    
    cp1.send('你好,子进程');
    

    1.js的代码:

    process.on('message', function (data) {
        console.log('父进程发送的 : ', data.toString());
    });
    //向父进程发送消息
    process.send('你好,父进程');
    

    默认情况下,只有子进程全部退出了,父进程才能退出。我们希望父进程退出了,子进程仍然独立运行。可以通过设置 detached 为 true。

    默认情况下,父进程会等待所有子程退出后,才退出。通过使用 unref() 让父进程无需等待子进程就可直接退出。

    const {spawn} = require('child_process');
    const fs = require('fs');
    let fd = fs.openSync('./1.txt', 'w', 0o666);
    
    let cp1 = spawn('node', ['1.js'], {
        cwd: process.cwd(),
        //注意这里,把不需要的设置为ignore,不然主进程仍然会阻塞等待子进程
        stdio: ['ignore', fd, 'ignore'],
        detached: true
    });
    
    cp1.on('error', function (err) {
        console.log(err);
    });
    
    //解绑子进程,让父进程不用等待子进程
    cp1.unref();
    

    1.js的代码:

    let i = 0;
    let timer = setInterval(function () {
        if (i > 20) {
            clearInterval(timer);
        }
        process.stdout.write('写入数据' + i + '
    ');
        i++;
    }, 1000);
    

      

    2、通过 fork() 创建子进程

    fork() 是 spawn() 的特殊情况,用于创建新的进程,默认建立一个IPC通信通道,允许父进程与子进程进行消息传递。

    fork() 返回一个子进程对象,子进程输入/输出操作执行完毕后,父进程不退出,子进程不会自动退出,需调用 exit() 显式退出。

    const {fork} = require('child_process');
    
    //参数一表示,运行的模块
    //参数二表示,参数列表
    //参数三表示,创建子进程的配置
    let cp1 = fork('2.js', ['1', '2', '3'], {
        //子进程的工作目录
        cwd: process.cwd(),
        //子进程的环境变量
        env: process.env,
        //运行模块的可执行文件
        execPath: process.execPath,
        //传递给可执行文件的参数列表
        execArgv: process.execArgv,
        //为false表示父进程与子进程共享标准(输入/输出),为true时不共享。
        silent: false
    });
    
    cp1.on('error', function (err) {
        console.log(err);
    });
    

    2.js的代码:

    for (let i = 0; i < process.argv.length; i++) {
        process.stdout.write(process.argv[i] + '
    ');
    }
    

    父进程与子进程间,通过 send() 和 'message'事件来传递消息。

    const {fork} = require('child_process');
    
    let cp1 = fork('2.js', [], {
        cwd: process.cwd(),
        env: process.env,
        silent: false
    });
    
    //接收消息
    cp1.on('message', function (data) {
        console.log('父进程收到 : ', JSON.stringify(data));
        process.exit(0);
    });
    //发送消息
    cp1.send({name: '你好子进程'});
    

    2.js的代码:

    process.on('message', function (data) {
        console.log('子进程收到 : ', JSON.stringify(data));
        process.send({name: '你好父进程'});
    });
    

      

    3、通过exec() 创建子进程

    exec() 可以开启一个子进程运行命令,并缓存子进程的输出结果。

    const {exec} = require('child_process');
    
    //参数一表示,要运行的命令
    //参数二表示,配置选项
    //参数三表示,进程终止时的回调
    exec('dir', {
        //子进程的工作目录
        cwd: process.cwd(),
        //子进程的环境变量
        env: process.env,
        //输出的编码
        encoding: 'utf8',
        //超时时间
        timeout: 60 * 1000,
        //缓存stdout,stderr最大的字节数
        maxBuffer: 1024 * 1024,
        //关闭子进程的信号
        killSignal: 'SIGTERM'
    }, function (err, stdout, stderr) {
        console.log(stdout.toString());
    });
    

      

     4、通过 execFile() 创建子进程

    使用 execFile() 开启一个运行可执行文件的子进程。

    const {execFile} = require('child_process');
    
    //参数一表示,可执行文件的名称或路径
    //参数二表示,参数列表
    //参数三表示,配置选项
    //参数四表示,进程终止时的回调
    let cp1 = execFile('node', ['3.js', '1', '2', '3'], {
        //子进程的工作目录
        cwd: process.cwd(),
        //子进程的环境变量
        env: process.env,
        //输出的编码
        encoding: 'utf8',
        //超时时间
        timeout: 60 * 1000,
        //缓存stdout,stderr最大的字节数
        maxBuffer: 1024 * 1024,
        //关闭子进程的信号
        killSignal: 'SIGTERM'
    }, function (err, stdout, stderr) {
        if (err) {
            console.log(err);
            process.exit();
        }
        console.log('子进程的输出 : ', stdout.toString());
    });
    
    cp1.on('error', function (err) {
        console.log(err);
    });
    

    3.js的代码:

    process.argv.forEach(function (value) {
        process.stdout.write(value + '
    ');
    });
    

      

    fork(),exec(),execFile() 都是基于 spawn() 的封装。

  • 相关阅读:
    padStart()方法,padEnd()方法
    模板字符串
    Flask ==》 信号 and flash-session
    单例模式
    Git == > 版本控制
    Flask ==> 文件配置
    setitem和getitem和delitem
    Flask ==> 简单用户登录
    Flask
    Django ==> Model基础
  • 原文地址:https://www.cnblogs.com/jkko123/p/10273329.html
Copyright © 2011-2022 走看看