zoukankan      html  css  js  c++  java
  • child_process小解

    js是一种单进程单线程的语言,但现行的cpu都是多核的,为了解决单进程单线程对多核使用不足的问题,child_process应运而生,理想情况下每个进程各自利用一个内核。

    主要有四种方法来创建子进程,每个子进程带有3个流对象child.stdin, child.stdout, child.stderr。

    exec 从子进程中返回一个完整的buffer,默认情况下为200k,若数据大于200k,会导致程序崩溃,适用于少量数据返回的情况,属于“同步中的异步”,即直到完全读取到内容,才会从子进程返回数据

    execFile 与exec类似,不同之处就是它创建子进程只需要指定要执行的文件模块即可

    spawn(大量生产) 返回一个stream对象,因此当你想要子进程返回大量数据时,例如图像处理,读取二进制数据等,最好使用此方法,此方法属于“异步中的异步”,这意味着从子进程开始执行开始,就开始有数据流从子进程传输给node

    fork(分配) 与spawn类似,不同之处就是它创建子进程只需要指定要执行的文件模块即可,而且它会在父进程和子进程之间建立一个通信通道

    对于child.stdin, child.stdout, child.stderr,都是stream对象,其具备stream对象的所有时间,data,error等

    对于进程,拥有close,exit,error等事件

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    child_process.exec(command[, options], callback)

    解析:

    command 将要运行的命令

    options 可以是

     cwd 当前子进程的目录

     env  环境变量键值对

     encoding 编码方式,默认‘utf-8’

     shell 将要执行命令的shell

     timeout 超时时间,默认0

     maxBuffer 数字,stdout与stderr中允许的最大缓存(二进制),超过此值子进程会被杀死,默认200k

     killSignal 字符串,结束信号

     uid 数字,设置用户进程id

     gid 数字,设置进程组id

    callback回调函数,包含三个参数(err, stdout, stderr) stdout子进程标准输出,stderr子进程错误输出

    注: command与options各参数之间用空格分开,共同拼接成一个字符串

    eg:

    support.js 文件代码:
    //子进程输出 console.log(
    "进程 " + process.argv[2] + " 执行。" );
    master.js 文件代码: const fs
    = require('fs'); const child_process = require('child_process'); for(var i=0; i<3; i++) {
      //执行node命令, 当前子进程目录为support.js,用户进程id为当前的i,用空格隔开
    var workerProcess = child_process.exec('node support.js '+i, function (error, stdout, stderr) { if (error) { console.log(error.stack); console.log('Error code: '+error.code); console.log('Signal received: '+error.signal); } console.log('stdout: ' + stdout); console.log('stderr: ' + stderr); }); workerProcess.on('exit', function (code) { console.log('子进程已退出,退出码 '+code); }); } 执行以上代码,输出结果为: $ node master.js 子进程已退出,退出码 0 stdout: 进程 1 执行。 stderr: 子进程已退出,退出码 0 stdout: 进程 0 执行。 stderr: 子进程已退出,退出码 0 stdout: 进程 2 执行。 stderr:

    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

     child_process.execFile(file[, args][, options][, callback])

    file: 子进程将要执行的文件目录

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    child_process.spawn(command [, args][, options])

    args 参数数组

    options

     cwd 当前子进程目录

     env 环境变量键值对

     stdio Array|String 子进程的 stdio 配置

     detached Boolean 这个子进程将会变成进程组的领导

     uid Number 设置用户进程的 ID

     gid Number 设置进程组的 ID

    注: command为字符串,options为数组

    eg: 

    //support.js 文件代码:
    console.log("进程 " + process.argv[2] + " 执行。" );
    //master.js 文件代码:
    const fs = require('fs');
    const child_process = require('child_process');
     
    for(var i=0; i<3; i++) {
      //command为node, 当前子进程文件为support.js, 进程id为当前i
    var workerProcess = child_process.spawn('node', ['support.js', i]);   //不可采用workProcess.on('data', function(){})的写法,这是常见概念错误 workerProcess.stdout.on('data', function (data) { console.log('stdout: ' + data); }); workerProcess.stderr.on('data', function (data) { console.log('stderr: ' + data); }); workerProcess.on('close', function (code) { console.log('子进程已退出,退出码 '+code); }); } 执行以上代码,输出结果为: $ node master.js stdout: 进程 0 执行。 子进程已退出,退出码 0 stdout: 进程 1 执行。 子进程已退出,退出码 0 stdout: 进程 2 执行。 子进程已退出,退出码 0

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    child_process.fork(modulePath[, args][, options])

    modulePath: string,将要运行的模块

    options:Object

     cwd String 子进程的当前工作目录

     env Object 环境变量键值对

     execPath String 创建子进程的可执行文件

     execArgv Array 子进程的可执行文件的字符串参数数组(默认: process.execArgv)

     silent Boolean 如果为true,子进程的stdinstdoutstderr将会被关联至父进程,否则,它们将会从父进程中继承。(默认为:false

     uid Number 设置用户进程的 ID

     gid Number 设置进程组的 ID

    eg:

    //support.js 文件代码:
    console.log("进程 " + process.argv[2] + " 执行。" );
    //master.js 文件代码:
    const fs = require('fs');
    const child_process = require('child_process');
     
    for(var i=0; i<3; i++) {
       var worker_process = child_process.fork("support.js", [i]);    
    
       worker_process.on('close', function (code) {
          console.log('子进程已退出,退出码 ' + code);
       });
    }
    执行以上代码,输出结果为:
    $ node master.js 
    进程 0 执行。
    子进程已退出,退出码 0
    进程 1 执行。
    子进程已退出,退出码 0
    进程 2 执行。
    子进程已退出,退出码 0

    进程间通信

    通过fork()或者其他API,创建子进程后,为了实现父子进程的通信,两者之间会建立IPC通道,通过此通道,父子进程之间才能通过send()与message()传递信息

    eg:

    //parent.js

    var cp= require('child_process');

    //创建子进程后n成为父进程

    var n= cp.fork(__dirname+ '/sub.js');

    n.on('message', function(m){

      console.log('parent got message:', m);

    })

    n.send({hello: 'world'})

    //sub.js

    //process对象代表当前进程

    process.on('message', function(m){

      console.log('child got message:', m);

    });

    process.send({foo: 'bar'});

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    句柄传递

    什么是句柄?句柄是一种用来标识资源的引用,它的内部包含指向对象的文件描述符,例如它能标识socket对象,UDP套接字,管道

    传递方法: 利用send()

    child.send(message, [,sendHandle])

    目前send()可发送的句柄类型有以下几种:

     net.Socket TCP套接字

     net.Server TCP服务器

     net.Native C++层面的TCP套接字或IPC管道

     dgram.Socket UDP套接字

     dgram.Native C++层面的UDP套接字

    eg:

    //创建服务器代理
    //parent.js
    var cp= require("child_process");
    var child1= cp.fork("child.js");
    var child2= cp.fork("child.js");

    var server= require("net").createServer();
    server.listen(1337, function(){
      //将tcp服务器传递给子进程
      child1.send('server', server);
      child2.send('server', server);
      //关闭父进程
      server.close();
    })


    //child.js
    var http= require('http');
    var server= http.createServer(function (req, res){
      //connection事件触发时输出
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.end('handled by child, pid is'+ process.pid+ ' ');
    });

    process.on("message", function(m, tcp){
      if(m== "server"){
        tcp.on("connection", function(socket){
          //http服务器发送connection事件
          server.emit('connection', socket);
        })
      }
    })

     ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    进程事件

    kill()并不能真正地将通过IPC相连的子进程杀死,而只是给子进程发送一个系统信号,默认情况下,父进程会通过此方法给子进程发送SIGTERM信号(signal terminate终结信号),子进程收到此信号后应当自己退出

    主要有两种形式

    //结束子进程

    child.kill([signal]);

    //结束当前进程

    process.kill(pid, [signal])

    eg:

    process.on('SIGTERM', function(){
    
      console.log('GOT a SIGTERM, exiting...');
    
      process.exit(1);
    
    });
    
    process.kill(process.pid, 'SIGTERM');
  • 相关阅读:
    Go语言中new()和 make()的区别详解
    对于Linux内核tty设备的一点理解
    中国移动MySQL数据库优化最佳实践
    深入分析Linux自旋锁
    JAVA大数据项目+整理的Mysql数据库32条军规
    MySQL DBA面试全揭秘
    LINUX 内核基础
    子查询
    linuxprobe----LINUX 基础课程目录学习
    从事分布式系统,计算,hadoop
  • 原文地址:https://www.cnblogs.com/yanze/p/6137682.html
Copyright © 2011-2022 走看看