在 Node.js 中,可以使用多個進程來處理文件,併發執行任務以提高性能和效率。多進程可以提高應用程序的性能和可靠性,但同時也會帶來一些額外的開銷和複雜性問題
優點
可以高效利用多核 CPU ,將許多併發請求分配到不同的進程中處理,來提高應用程序性能。
提高可靠性,多進程互相隔離,當一個進程崩潰或出現問題時,其他進程應該能夠繼續工作,不會影響整個應用程序的運行。
缺點
多進程開銷更大,需要更多的內存和 CPU 資源來維護進程通信和進程間數據同步。
多進程本身就是一種分佈式運行模式,會增加維護和調試難度
進程間通信和信息同步複雜,可能導致性能與內存問題。
具體有兩種方式:
- 使用
child_process
模塊:child_process
模塊允許你創建子進程並與其進行通信。你可以使用child_process.fork()
方法創建多個子進程,每個子進程負責處理一個文件或一組文件。通過進程間的消息傳遞,我們可以在主進程和子進程之間共享數據和任務。這種方式適用於文件處理任務比較獨立且相互之間沒有太多的依賴關係的情況。 - 使用進程池:進程池是一組預先創建的子進程,可以通過將任務分配給空閒的子進程來提高處理能力。我們可以使用
worker_threads
模塊來創建進程池。
下面實例中分別使用了child_process(async_process 方法)創建子進程與worker_threads(assignTaskToWorkers 方法)創建進程池:
process.js:
import ipcMain from '../ipcMain'; const { fork } = require('child_process'); const { Worker } = require('worker_threads'); const path = require('path'); class FileProcess { constructor() { this.process = null; this.workerPool = new Set(); ipcMain.ipc.on("async_update_file", this.async_update_file.bind(this)) } async_update_file(event, arg) { const files = arg.files; if(files.length === 1) { this.async_process(files[0]); } else { this.assignTaskToWorkers(files); } } async_process(file) { // 創建子進程 const childPath = path.join(process.cwd(), '/src/main/process/fileProcessor.js'); const child = fork(childPath); // 向子進程發送消息 child.send(file); // 監聽子進程的消息 child.on('message', (data) => { console.log(`子進程返回結果:${data}`); }); // 監聽子進程的錯誤 child.on('error', (error) => { console.error(`子進程發生錯誤:${error}`); }); } // 添加任務到進程池 addToWorkerPool(file) { const childPath = path.join(process.cwd(), '/src/main/process/fileWorker.js'); const worker = new Worker(childPath, { workerData: file }); worker.on('message', (data) => { console.log(`子進程返回結果:${data}`); this.workerPool.delete(worker); worker.unref(); }); worker.on('error', (error) => { console.error(`子進程發生錯誤:${error}`); this.workerPool.delete(worker); worker.unref(); }); this.workerPool.add(worker); // console.log('this.workerPool', this.workerPool) } // 分配任務到進程池 assignTaskToWorkers(files) { files.forEach((file) => this.addToWorkerPool(file)); } } export default FileProcess;
fileProcessor.js
const fs = require('fs'); process.on('message', (file) => { console.log('file=======', file) // 處理文件 try { const data = fs.readFileSync(file, 'utf8'); const processedData = processData(data); process.send(processedData); } catch (error) { process.send(`文件處理出錯:${error.message}`); } }); function processData(data) { // 進行文件處理邏輯示例 return data.toUpperCase(); }
fileWorker.js
const { workerData, parentPort } = require('worker_threads'); const fs = require('fs'); // 讀取 workerData 中指定的文件 const file = fs.readFileSync(workerData, 'utf8'); // 處理數據(此處只是簡單地轉換爲大寫字母) const upperCaseData = file.toUpperCase(); // 返回處理結果 parentPort.postMessage(upperCaseData);
async_process