Nodejs 多進程多線程和線程通信以及應用和原理


Nodejs以事件驅動、非阻塞式I/O的模型,擅長IO密集型操作。

早期版本提供了child_processcluster(V0.6.0)來提供多進程的支持。
v10版本實驗性的引入worker_threads,Nodejs具有多線程的支持,終於在v12.11.0正式穩定

下面講解Nodejs多進程,多線程應用,后續在補充進程,線程實現方式

child_process 進程

const spawn = require('child_process').spawn
const ls = spawn('ls',['-lh','/user']) // ls -lh /user
ls.stdout.on('data',data => {
    console.log(`stdout: ${data}`)
})
ls.stderr.on('data', (data) => {
    console.log(`stderr: ${data}`)
})
ls.on('close', (code) => {
    console.log(`child process exited with code ${code}`)
})
  • .exec()、.execFile()、.fork()底層都是通過.spawn()實現的
  • 上面都是異步方法,有相應的同步方法,例如在子進程調用shell,需要使用同步的方式

下面是fork的使用,以及進程通信

// main.js
var child_process = require('child_process')
var child = child_process.fork('./child.js',{
    silent: false
})
child.on('message', function (m) {
    console.log('message from child: ' + JSON.stringify(m))
})
// child.js
process.on('message', function(m){
    console.log('message from parent: ' + JSON.stringify(m))
})
process.send({from: 'child'})

結果

> node main.js
message from child: {"from":"child"}
message from parent: {"from":"parent"}

cluster 進程

var cluster = require('cluster')
var http = require('http')
var numCPUs = require('os').cpus().length
if (cluster.isMaster) {
    console.log(`[master] master start...`)
    for (var i = 0; i < numCPUs; i++) {
        var worker = cluster.fork()
        worker.send(`hello I am master`)
    }
    cluster.on('exit', function (worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died')
        // cluster.fork() // 監聽work進程是否退出,退出就新建進程
    })
} else {
    process.on('message',function(p) {
        console.log(`[worker]: ${p}`)
        process.send('hi i am worker')
        process.exit(0) // 手動推出worker進程
    })
}

worker_threads 線程

const {
  isMainThread, parentPort, workerData, threadId,
  MessageChannel, MessagePort, Worker
} = require('worker_threads');
function mainThread() {
  const worker = new Worker(__filename, { workerData: 0 });
  worker.on('exit', code => { console.log(`main: worker stopped with exit code ${code}`); });
  worker.on('message', msg => {
    console.log(`main: receive ${msg}`);
    worker.postMessage(msg + 1);
  });
}
function workerThread() {
  console.log(`worker: threadId ${threadId} start with ${__filename}`);
  console.log(`worker: workerDate ${workerData}`);
  parentPort.on('message', msg => {
    console.log(`worker: receive ${msg}`);
    if (msg === 5) { process.exit(); }
    parentPort.postMessage(msg);
  }),
  parentPort.postMessage(workerData);
}
 
if (isMainThread) {
  mainThread();
} else {
  workerThread();
}

MessageChannel 通信方式

const {
  isMainThread, parentPort, workerData, threadId,
  MessageChannel, MessagePort, Worker
} = require('worker_threads');
 
if (isMainThread) {
  const worker1 = new Worker(__filename);
  const worker2 = new Worker(__filename);
  const subChannel = new MessageChannel();
  worker1.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1]);
  worker2.postMessage({ hereIsYourPort: subChannel.port2 }, [subChannel.port2]);
} else {
  parentPort.once('message', (value) => {
    value.hereIsYourPort.postMessage('hello');
    value.hereIsYourPort.on('message', msg => {
      console.log(`thread ${threadId}: receive ${msg}`);
    });
  });
}

參考
Nodejs進階:如何玩轉子進程(child_process)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM