• 售前

  • 售后

热门帖子
入门百科

在nodejs中创建child process的方法

[复制链接]
伊索谗言 显示全部楼层 发表于 2021-10-25 20:30:51 |阅读模式 打印 上一主题 下一主题
目次


  • 简介
  • child process
  • 异步创建进程
  • 同步创建进程

简介

nodejs的main event loop是单线程的,nodejs自己也维护着Worker Pool用来处置惩罚一些耗时的操纵,我们还可以通过使用nodejs提供的worker_threads来手动创建新的线程来实行自己的使命。
本文将会先容一种新的实行nodejs使命的方式,child process。

child process

lib/child_process.js提供了child_process模块,通过child_process我们可以创建子进程。
留意,worker_threads创建的是子线程,而child_process创建的是子进程。
在child_process模块中,可以同步创建进程也可以异步创建进程。同步创建方式只是在异步创建的方法后面加上Sync。
创建出来的进程用ChildProcess类来表现。
我们看下ChildProcess的界说:
  1. interface ChildProcess extends events.EventEmitter {
  2. stdin: Writable | null;
  3. stdout: Readable | null;
  4. stderr: Readable | null;
  5. readonly channel?: Pipe | null;
  6. readonly stdio: [
  7.   Writable | null, // stdin
  8.   Readable | null, // stdout
  9.   Readable | null, // stderr
  10.   Readable | Writable | null | undefined, // extra
  11.   Readable | Writable | null | undefined // extra
  12. ];
  13. readonly killed: boolean;
  14. readonly pid: number;
  15. readonly connected: boolean;
  16. readonly exitCode: number | null;
  17. readonly signalCode: NodeJS.Signals | null;
  18. readonly spawnargs: string[];
  19. readonly spawnfile: string;
  20. kill(signal?: NodeJS.Signals | number): boolean;
  21. send(message: Serializable, callback?: (error: Error | null) => void): boolean;
  22. send(message: Serializable, sendHandle?: SendHandle, callback?: (error: Error | null) => void): boolean;
  23. send(message: Serializable, sendHandle?: SendHandle, options?: MessageOptions, callback?: (error: Error | null) => void): boolean;
  24. disconnect(): void;
  25. unref(): void;
  26. ref(): void;
  27. /**
  28.   * events.EventEmitter
  29.   * 1. close
  30.   * 2. disconnect
  31.   * 3. error
  32.   * 4. exit
  33.   * 5. message
  34.   */
  35. ...
  36. }
复制代码
可以看到ChildProcess也是一个EventEmitter,以是它可以发送和接受event。
ChildProcess可以接收到event有5种,分别是close,disconnect,error,exit和message。
当调用父进程中的 subprocess.disconnect() 或子进程中的 process.disconnect() 后会触发 disconnect 事件。
当出现无法创建进程,无法kill进程和向子进程发送消息失败的时间都会触发error事件。
当子进程竣过后时会触发exit事件。
当子进程的 stdio 流被关闭时会触发 close 事件。 留意,close事件和exit事件是差别的,由于多个进程大概共享同一个stdio,以是发送exit事件并不肯定会触发close事件。
看一个close和exit的例子:
  1. const { spawn } = require('child_process');
  2. const ls = spawn('ls', ['-lh', '/usr']);
  3. ls.stdout.on('data', (data) => {
  4. console.log(`stdout: ${data}`);
  5. });
  6. ls.on('close', (code) => {
  7. console.log(`子进程使用代码 $[code] 关闭所有 stdio`);
  8. });
  9. ls.on('exit', (code) => {
  10. console.log(`子进程使用代码 $[code] 退出`);
  11. });
复制代码
末了是message事件,当子进程使用process.send() 发送消息的时间就会被触发。
ChildProcess中有几个标准流属性,分别是stderr,stdout,stdin和stdio。
stderr,stdout,stdin很好理解,分别是标准错误,标准输出和标准输入。
我们看一个stdout的使用:
  1. const { spawn } = require('child_process');
  2. const subprocess = spawn('ls');
  3. subprocess.stdout.on('data', (data) => {
  4. console.log(`接收到数据块 ${data}`);
  5. });
复制代码
stdio现实上是stderr,stdout,stdin的聚集:
  1. readonly stdio: [
  2.   Writable | null, // stdin
  3.   Readable | null, // stdout
  4.   Readable | null, // stderr
  5.   Readable | Writable | null | undefined, // extra
  6.   Readable | Writable | null | undefined // extra
  7. ];
复制代码
此中stdio[0]表现的是stdin,stdio[1]表现的是stdout,stdio[2]表现的是stderr。
如果在通过stdio创建子进程的时间,这三个标准流被设置为除pipe之外的其他值,那么stdin,stdout和stderr将为null。
我们看一个使用stdio的例子:
  1. const assert = require('assert');
  2. const fs = require('fs');
  3. const child_process = require('child_process');
  4. const subprocess = child_process.spawn('ls', {
  5. stdio: [
  6. 0, // 使用父进程的 stdin 用于子进程。
  7. 'pipe', // 把子进程的 stdout 通过管道传到父进程 。
  8. fs.openSync('err.out', 'w') // 把子进程的 stderr 定向到一个文件。
  9. ]
  10. });
  11. assert.strictEqual(subprocess.stdio[0], null);
  12. assert.strictEqual(subprocess.stdio[0], subprocess.stdin);
  13. assert(subprocess.stdout);
  14. assert.strictEqual(subprocess.stdio[1], subprocess.stdout);
  15. assert.strictEqual(subprocess.stdio[2], null);
  16. assert.strictEqual(subprocess.stdio[2], subprocess.stderr);
复制代码
通常情况下父进程中维护了一个对子进程的引用计数,只有在当子进程退出之后父进程才会退出。
这个引用就是ref,如果调用了unref方法,则答应父进程独立于子进程退出。
  1. const { spawn } = require('child_process');
  2. const subprocess = spawn(process.argv[0], ['child_program.js'], {
  3. detached: true,
  4. stdio: 'ignore'
  5. });
  6. subprocess.unref();
复制代码
末了,我们看一下怎样通过ChildProcess来发送消息:
  1. subprocess.send(message[, sendHandle[, options]][, callback])
复制代码
此中message就是要发送的消息,callback是发送消息之后的回调。
sendHandle比力特殊,它可以是一个TCP服务器或socket对象,通过将这些handle传递给子进程。子进程将会在message事件中,将该handle传递给Callback函数,从而可以在子进程中进行处置惩罚。
我们看一个传递TCP server的例子,首先看主进程:
  1. const subprocess = require('child_process').fork('subprocess.js');
  2. // 打开 server 对象,并发送该句柄。
  3. const server = require('net').createServer();
  4. server.on('connection', (socket) => {
  5. socket.end('由父进程处理');
  6. });
  7. server.listen(1337, () => {
  8. subprocess.send('server', server);
  9. });
复制代码
再看子进程:
  1. process.on('message', (m, server) => {
  2. if (m === 'server') {
  3. server.on('connection', (socket) => {
  4. socket.end('由子进程处理');
  5. });
  6. }
  7. });
复制代码
可以看到子进程接收到了server handle,并且在子进程中监听connection事件。
下面我们看一个传递socket对象的例子:
  1. onst { fork } = require('child_process');
  2. const normal = fork('subprocess.js', ['normal']);
  3. const special = fork('subprocess.js', ['special']);
  4. // 开启 server,并发送 socket 给子进程。
  5. // 使用 `pauseOnConnect` 防止 socket 在被发送到子进程之前被读取。
  6. const server = require('net').createServer({ pauseOnConnect: true });
  7. server.on('connection', (socket) => {
  8. // 特殊优先级。
  9. if (socket.remoteAddress === '74.125.127.100') {
  10. special.send('socket', socket);
  11. return;
  12. }
  13. // 普通优先级。
  14. normal.send('socket', socket);
  15. });
  16. server.listen(1337);
复制代码
subprocess.js的内容:
  1. process.on('message', (m, socket) => {
  2. if (m === 'socket') {
  3. if (socket) {
  4. // 检查客户端 socket 是否存在。
  5. // socket 在被发送与被子进程接收这段时间内可被关闭。
  6. socket.end(`请求使用 ${process.argv[2]} 优先级处理`);
  7. }
  8. }
  9. });
复制代码
主进程创建了两个subprocess,一个处置惩罚特殊的优先级, 一个处置惩罚普通的优先级。

异步创建进程

child_process模块有4种方式可以异步创建进程,分别是child_process.spawn()、child_process.fork()、child_process.exec() 和 child_process.execFile()。
先看一个各个方法的界说:
  1. child_process.spawn(command[, args][, options])
  2. child_process.fork(modulePath[, args][, options])
  3. child_process.exec(command[, options][, callback])
  4. child_process.execFile(file[, args][, options][, callback])
复制代码
此中child_process.spawn是根本,他会异步的生成一个新的进程,其他的fork,exec和execFile都是基于spawn来生成的。
fork会生成新的Node.js 进程。
exec和execFile是以新的进程实行新的下令,并且带有callback。他们的区别就在于在windows的情况中,如果要实行.bat或者.cmd文件,没有shell终端是实行不了的。这个时间就只能以exec来启动。execFile是无法实行的。
或者也可以使用spawn。
我们看一个在windows中使用spawn和exec的例子:
  1. // 仅在 Windows 上。
  2. const { spawn } = require('child_process');
  3. const bat = spawn('cmd.exe', ['/c', 'my.bat']);
  4. bat.stdout.on('data', (data) => {
  5. console.log(data.toString());
  6. });
  7. bat.stderr.on('data', (data) => {
  8. console.error(data.toString());
  9. });
  10. bat.on('exit', (code) => {
  11. console.log(`子进程退出,退出码 $[code]`);
  12. });
复制代码
  1. const { exec, spawn } = require('child_process');
  2. exec('my.bat', (err, stdout, stderr) => {
  3. if (err) {
  4. console.error(err);
  5. return;
  6. }
  7. console.log(stdout);
  8. });
  9. // 文件名中包含空格的脚本:
  10. const bat = spawn('"my script.cmd"', ['a', 'b'], { shell: true });
  11. // 或:
  12. exec('"my script.cmd" a b', (err, stdout, stderr) => {
  13. // ...
  14. });
复制代码
同步创建进程

同步创建进程可以使用child_process.spawnSync()、child_process.execSync() 和 child_process.execFileSync() ,同步的方法会壅闭 Node.js 事件循环、停息任何其他代码的实行,直到子进程退出。
通常对于一些脚本使命来说,使用同步创建进程会比力常用。
到此这篇关于在nodejs中创建child process的方法的文章就先容到这了,更多相关nodejs中创建child process内容请搜索草根技能分享以前的文章或继续浏览下面的相关文章盼望大家以后多多支持草根技能分享!

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作