nodejs에서childprocess를 만드는 방법

소개


nodejs의main 이벤트 루프는 단일 라인입니다. nodejs 자체도 Worker Pool을 유지하여 시간을 소모하는 작업을 처리하고 있습니다. 우리는 nodejs가 제공하는worker_를 사용할 수 있습니다threads는 자신의 작업을 수행하기 위해 수동으로 새 라인을 만듭니다.
본고는 nodejs 임무를 수행하는 새로운 방식인childprocess를 소개할 것입니다.

child process


lib/child_process.js 제공 child_process 모듈,child_를 통해프로세스는 하위 프로세스를 만들 수 있습니다.
주의,worker_threads가 만든 것은 하위 라인이고,child_프로세스가 만든 것은 하위 프로세스입니다.
child에서_프로세스 모듈에서 프로세스를 동기화할 수도 있고 비동기적으로 프로세스를 만들 수도 있습니다.동기식 생성 방식은 비동기식 생성 방법 뒤에 Sync만 추가합니다.
생성된 프로세스는 ChildProcess 클래스로 표시됩니다.
ChildProcess의 정의를 살펴보겠습니다.

interface ChildProcess extends events.EventEmitter {
 stdin: Writable | null;
 stdout: Readable | null;
 stderr: Readable | null;
 readonly channel?: Pipe | null;
 readonly stdio: [
  Writable | null, // stdin
  Readable | null, // stdout
  Readable | null, // stderr
  Readable | Writable | null | undefined, // extra
  Readable | Writable | null | undefined // extra
 ];
 readonly killed: boolean;
 readonly pid: number;
 readonly connected: boolean;
 readonly exitCode: number | null;
 readonly signalCode: NodeJS.Signals | null;
 readonly spawnargs: string[];
 readonly spawnfile: string;
 kill(signal?: NodeJS.Signals | number): boolean;
 send(message: Serializable, callback?: (error: Error | null) => void): boolean;
 send(message: Serializable, sendHandle?: SendHandle, callback?: (error: Error | null) => void): boolean;
 send(message: Serializable, sendHandle?: SendHandle, options?: MessageOptions, callback?: (error: Error | null) => void): boolean;
 disconnect(): void;
 unref(): void;
 ref(): void;

 /**
  * events.EventEmitter
  * 1. close
  * 2. disconnect
  * 3. error
  * 4. exit
  * 5. message
  */
 ...
 }
ChildProcess도 하나의 Event Emitter이기 때문에 이벤트를 보내고 받아들일 수 있습니다.
ChildProcess에서 이벤트를 받을 수 있는 것은 5가지입니다. 각각close,disconnect,error,exit,message입니다.
부모 프로세스의subprocess를 호출합니다.disconnect () 또는 하위 프로세스의process.disconnect () 후에 disconnect 이벤트를 터치합니다.
프로세스를 만들 수 없습니다.kill 프로세스와 하위 프로세스에 메시지를 보내는 데 실패했을 때 error 이벤트를 촉발합니다.
하위 프로세스가 끝나면 exit 이벤트를 터치합니다.
하위 프로세스의 stdio 흐름이 닫힐 때close 이벤트를 터치합니다.주의,close 이벤트와 exit 이벤트는 다르다. 여러 프로세스가 같은 stdio를 공유할 수 있기 때문에,exit 이벤트를 보내는 것이 반드시 close 이벤트를 촉발하는 것은 아니다.
close와 exit의 예를 보십시오.

const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
 console.log(`stdout: ${data}`);
});

ls.on('close', (code) => {
 console.log(`  $[code]   stdio`);
});

ls.on('exit', (code) => {
 console.log(`  $[code]  `);
});
마지막으로 메시지 이벤트입니다. 프로세스가 프로세스를 사용할 때입니다.send () 메시지를 보낼 때 촉발됩니다.
ChildProcess에는 stderr, stdout, stdin, stdio 등 몇 가지 표준 흐름 속성이 있습니다.
stderr, stdout, stdin은 표준 오류, 표준 출력과 표준 입력을 잘 이해합니다.
우리는 stdout의 사용을 보았다.

const { spawn } = require('child_process');

const subprocess = spawn('ls');

subprocess.stdout.on('data', (data) => {
 console.log(`  ${data}`);
});
stdio는 실제로 stderr, stdout, stdin의 집합입니다.

readonly stdio: [
  Writable | null, // stdin
  Readable | null, // stdout
  Readable | null, // stderr
  Readable | Writable | null | undefined, // extra
  Readable | Writable | null | undefined // extra
 ];
그 중에서 stdio[0]는 stdin을 나타내고 stdio[1]는 stdout를 나타내며 stdio[2]는 stderr를 나타낸다.
stdio를 통해 하위 프로세스를 만들 때, 이 세 가지 표준 흐름이pipe를 제외한 다른 값으로 설정되면, stdin, stdout, stderr는null이 됩니다.
stdio를 사용하는 예를 보겠습니다.

const assert = require('assert');
const fs = require('fs');
const child_process = require('child_process');

const subprocess = child_process.spawn('ls', {
 stdio: [
 0, //   stdin  。
 'pipe', //   stdout   。
 fs.openSync('err.out', 'w') //   stderr  。
 ]
});

assert.strictEqual(subprocess.stdio[0], null);
assert.strictEqual(subprocess.stdio[0], subprocess.stdin);

assert(subprocess.stdout);
assert.strictEqual(subprocess.stdio[1], subprocess.stdout);

assert.strictEqual(subprocess.stdio[2], null);
assert.strictEqual(subprocess.stdio[2], subprocess.stderr);
일반적으로 부모 프로세스는 하위 프로세스에 대한 인용 계수를 유지합니다. 하위 프로세스가 종료된 후에만 부모 프로세스가 종료됩니다.
이 인용은ref입니다. unref 방법을 사용하면 부모 프로세스가 하위 프로세스에서 독립적으로 종료할 수 있습니다.

const { spawn } = require('child_process');

const subprocess = spawn(process.argv[0], ['child_program.js'], {
 detached: true,
 stdio: 'ignore'
});

subprocess.unref();
마지막으로 ChildProcess를 통해 메시지를 보내는 방법을 살펴보겠습니다.

subprocess.send(message[, sendHandle[, options]][, callback])
그 중에서 메시지는 메시지를 보내는 것이고, 콜백은 메시지를 보낸 후의 리셋입니다.
sendHandle은 TCP 서버나 socket 대상이 될 수 있습니다. 이 Handle을 하위 프로세스에 전달합니다.하위 프로세스는 메시지 이벤트에서 이handle을 Callback 함수에 전달하여 하위 프로세스에서 처리할 수 있습니다.
TCP 서버를 전달하는 예를 살펴보겠습니다. 우선 메인 프로세스를 살펴보겠습니다.

const subprocess = require('child_process').fork('subprocess.js');

//   server  , 。
const server = require('net').createServer();
server.on('connection', (socket) => {
 socket.end(' ');
});
server.listen(1337, () => {
 subprocess.send('server', server);
});
하위 프로세스를 보려면:

process.on('message', (m, server) => {
 if (m === 'server') {
 server.on('connection', (socket) => {
 socket.end(' ');
 });
 }
});
하위 프로세스가 서버handle을 수신하고 하위 프로세스에서connection 이벤트를 감청하는 것을 볼 수 있습니다.
다음은 socket 대상을 전달하는 예입니다.

onst { fork } = require('child_process');
const normal = fork('subprocess.js', ['normal']);
const special = fork('subprocess.js', ['special']);

//   server,  socket  。
//   `pauseOnConnect`   socket  。
const server = require('net').createServer({ pauseOnConnect: true });
server.on('connection', (socket) => {

 //  。
 if (socket.remoteAddress === '74.125.127.100') {
 special.send('socket', socket);
 return;
 }
 //  。
 normal.send('socket', socket);
});
server.listen(1337);
subprocess.js의 내용:

process.on('message', (m, socket) => {
 if (m === 'socket') {
 if (socket) {
 //   socket  。
 // socket  。
 socket.end(`  ${process.argv[2]}  `);
 }
 }
});
메인 프로세스는 두 개의subprocess를 만들었습니다. 하나는 특수한 우선 순위를 처리하고, 하나는 일반적인 우선 순위를 처리합니다.

비동기식 프로세스 생성


child_프로세스 모듈은 4가지 방식으로 비동기적으로 프로세스를 만들 수 있습니다. 각각child_process.spawn()、child_process.fork()、child_process.exec() 및child_process.execFile().
먼저 각 방법의 정의를 살펴보자.

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

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

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

child_process.execFile(file[, args][, options][, callback])
그중 child_process.spawn은 기초입니다. 다른 fork,exec,execFile은 모두spawn을 바탕으로 생성됩니다.
fork는 새로운 Node를 생성합니다.js 프로세스.
exec와 execFile은 새로운 프로세스로 새 명령을 실행하고callback을 가지고 있습니다.그들의 차이는 윈도우즈 환경에서 실행하려면 다음과 같다.bat 또는.cmd 파일, 셸 단말기가 없으면 실행할 수 없습니다.이럴 때는exec로만 시작할 수 있습니다.execFile은 실행할 수 없습니다.
아니면 spawn을 사용할 수도 있습니다.
윈도우즈에서spawn과exec를 사용하는 예를 보겠습니다.

//   Windows  。
const { spawn } = require('child_process');
const bat = spawn('cmd.exe', ['/c', 'my.bat']);

bat.stdout.on('data', (data) => {
 console.log(data.toString());
});

bat.stderr.on('data', (data) => {
 console.error(data.toString());
});

bat.on('exit', (code) => {
 console.log(` ,  $[code]`);
});

const { exec, spawn } = require('child_process');
exec('my.bat', (err, stdout, stderr) => {
 if (err) {
 console.error(err);
 return;
 }
 console.log(stdout);
});

//  :
const bat = spawn('"my script.cmd"', ['a', 'b'], { shell: true });
//  :
exec('"my script.cmd" a b', (err, stdout, stderr) => {
 // ...
});

프로세스 동기화


동기화 생성 프로세스는child_process.spawnSync()、child_process.execSync() 및 child_process.execFileSync(), 동기화 방법이 Node를 차단합니다.js 이벤트는 하위 프로세스가 끝날 때까지 다른 코드의 실행을 멈추고 순환합니다.
일반적으로 일부 스크립트 작업에 있어서 동기화 프로세스를 사용하면 비교적 자주 사용됩니다.
이 글은 nodejs에서childprocess를 만드는 방법에 대한 소개입니다. 더 많은 nodejs에서childprocess를 만드는 내용은 이전의 글을 검색하거나 아래의 관련 글을 계속 훑어보십시오. 앞으로 많은 응원 부탁드립니다!

좋은 웹페이지 즐겨찾기