中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何在nodejs中創建一個child process方法

發布時間:2021-01-26 14:08:34 來源:億速云 閱讀:193 作者:Leah 欄目:開發技術

本篇文章為大家展示了如何在nodejs中創建一個child process方法,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

簡介

nodejs的main event loop是單線程的,nodejs本身也維護著Worker Pool用來處理一些耗時的操作,我們還可以通過使用nodejs提供的worker_threads來手動創建新的線程來執行自己的任務。

child process

lib/child_process.js提供了child_process模塊,通過child_process我們可以創建子進程。

注意,worker_threads創建的是子線程,而child_process創建的是子進程。

在child_process模塊中,可以同步創建進程也可以異步創建進程。同步創建方式只是在異步創建的方法后面加上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也是一個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的例子:

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] 退出`);
});

最后是message事件,當子進程使用process.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])

其中message就是要發送的消息,callback是發送消息之后的回調。

sendHandle比較特殊,它可以是一個TCP服務器或socket對象,通過將這些handle傳遞給子進程。子進程將會在message事件中,將該handle傳遞給Callback函數,從而可以在子進程中進行處理。

我們看一個傳遞TCP server的例子,首先看主進程:

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('由子進程處理');
 });
 }
});

可以看到子進程接收到了server 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_process模塊有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。他們的區別就在于在windows的環境中,如果要執行.bat或者.cmd文件,沒有shell終端是執行不了的。這個時候就只能以exec來啟動。execFile是無法執行的。

或者也可以使用spawn。

我們看一個在windows中使用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中創建一個child process方法,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

渭源县| 通山县| 宜兰市| 金山区| 时尚| 玉田县| 汉川市| 凤山县| 东丽区| 泉州市| 梁山县| 会同县| 随州市| 启东市| 桓台县| 周宁县| 陵川县| 永登县| 长宁县| 铜陵市| 揭西县| 赤峰市| 铜川市| 井陉县| 宁德市| 光山县| 兴业县| 高要市| 竹山县| 岳阳县| 梁山县| 莱阳市| 建德市| 通辽市| 武山县| 拉孜县| 临湘市| 集贤县| 渭源县| 商城县| 唐山市|