目錄
先決條件
在本節使用具體範例介紹
在本節中,讓我們看一下CPU密集型範例,產生斐波那契數列
结论
思考
首頁 web前端 js教程 聊聊Node.js + worker_threads如何實作多執行緒? (詳解)

聊聊Node.js + worker_threads如何實作多執行緒? (詳解)

Feb 11, 2022 pm 08:07 PM
node.js 多執行緒

本篇文章帶大家了解一下worker_threads 模組,介紹一下在Node中如何使用worker_threads實現多線程,以及利用worker_threads執行斐波那契數列作為實踐例子,希望對大家有所幫助!

聊聊Node.js + worker_threads如何實作多執行緒? (詳解)

通常情況下,Node.js被認為是單執行緒。由主執行緒去依照編碼順序一步一步執行程式碼,一旦遇到同步程式碼阻塞,主執行緒就會被佔用,後續的程式碼的執行都會被卡住。沒錯Node.js的單線程指的是主線程是"單線程"。

為了解決單一執行緒帶來的問題,本文的主角worker_threads出現了。 worker_threads首次在Node.js v10.5.0作為實驗性功能出現,需要命令列帶上--experimental-worker才能使用。直到v12.11.0穩定版才能正式使用。

本文將會介紹worker_threads的使用方式,以及利用worker_threads執行斐波那契數列作為實作範例。

先決條件

閱讀並食用本文,需要先具備:

    ##安裝了
  • Node.js v12.11.0 以上版本
  • 掌握JavaScript 同步與非同步程式設計的基礎知識
  • 掌握Node.js 的工作原理

worker_threads 介紹

worker_threads 模組允許使用並行執行JavaScript 的執行緒。

工作執行緒對於執行 CPU 密集型的 JavaScript 操作很有用。它們對 I/O 密集型的工作幫助不大。 Node.js 內建的非同步 I/O 操作比工作執行緒更有效率。

與 

child_process 或 cluster 不同,worker_threads 可以共享記憶體。它們透過傳輸 ArrayBuffer 實例或共享 SharedArrayBuffer 實例來實現。

由於以下特性,

worker_threads已被證明是充分利用CPU效能的最佳解決方案:

    ##它們運行具有多個執行緒的單一進程。
  • 每個執行緒執行一個事件循環。
  • 每個執行緒執行單一 JS 引擎實例。
  • 每個執行緒執行單一
  • Nodejs

    實例。

worker_threads 如何運作

worker_threads

透過執行主執行緒指定的腳本檔案來工作。每個執行緒都在與其他執行緒隔離的情況下執行。但是,這些線程可以透過訊息通道來回傳遞訊息。

主執行緒

使用worker.postMessage()函數使用訊息通道,而工作執行緒使用parentPort.postMessage()函數。

透過官方範例程式碼加強了解:

const {
  Worker, isMainThread, parentPort, workerData
} = require('worker_threads');

if (isMainThread) {
  module.exports = function parseJSAsync(script) {
    return new Promise((resolve, reject) => {
      const worker = new Worker(__filename, {
        workerData: script
      });
      worker.on('message', resolve);
      worker.on('error', reject);
      worker.on('exit', (code) => {
        if (code !== 0)
          reject(new Error(`Worker stopped with exit code ${code}`));
      });
    });
  };
} else {
  const { parse } = require('some-js-parsing-library');
  const script = workerData;
  parentPort.postMessage(parse(script));
}
登入後複製
上述程式碼

主執行緒

工作執行緒都使用同一份檔案作為執行腳本(__filename為目前執行檔路徑),透過isMainThread來區分主執行緒工作執行緒運行時邏輯。當模組對外暴露方法parseJSAsync被呼叫時候,都會衍生子工作執行緒去執行呼叫parse函數。

worker_threads 具體使用

在本節使用具體範例介紹

worker_threads

的使用##「建立工作執行緒

腳本檔案

workerExample.js:

const { workerData, parentPort } = require('worker_threads')
parentPort.postMessage({ welcome: workerData })
登入後複製
建立主執行緒

腳本檔案

main.js:

const { Worker } = require('worker_threads')

const runWorker = (workerData) => {
    return new Promise((resolve, reject) => {
        // 引入 workerExample.js `工作线程`脚本文件
        const worker = new Worker('./workerExample.js', { workerData });
        worker.on('message', resolve);
        worker.on('error', reject);
        worker.on('exit', (code) => {
            if (code !== 0)
                reject(new Error(`stopped with  ${code} exit code`));
        })
    })
}

const main = async () => {
    const result = await runWorker('hello worker threads')
    console.log(result);
}

main().catch(err => console.error(err))
登入後複製
控制台命令列執行:
node main.js
登入後複製
登入後複製

輸出:

{ welcome: 'hello worker threads' }
登入後複製

worker_threads 運算斐波那契數列

在本節中,讓我們看一下CPU密集型範例,產生斐波那契數列

如果在沒有工作執行緒的情況下完成此任務,則會隨著nth

期限的增加而阻塞主執行緒。

建立工作執行緒

腳本檔案

worker.js

const {parentPort, workerData} = require("worker_threads");

parentPort.postMessage(getFibonacciNumber(workerData.num))

function getFibonacciNumber(num) {
    if (num === 0) {
        return 0;
    }
    else if (num === 1) {
        return 1;
    }
    else {
        return getFibonacciNumber(num - 1) + getFibonacciNumber(num - 2);
    }
}
登入後複製
建立主執行緒

腳本檔案

main.js :

const {Worker} = require("worker_threads");

let number = 30;

const worker = new Worker("./worker.js", {workerData: {num: number}});

worker.once("message", result => {
    console.log(`${number}th Fibonacci Result: ${result}`);
});

worker.on("error", error => {
    console.log(error);
});

worker.on("exit", exitCode => {
    console.log(`It exited with code ${exitCode}`);
})

console.log("Execution in main thread");
登入後複製
控制台命令列執行:
node main.js
登入後複製
登入後複製

輸出:

Execution in main thread
30th Fibonacci Result: 832040
It exited with code 0
登入後複製

main.js

檔案中,我們從類別的實例會建立一個工作線程,

Worker正如我們在前面的範例中看到的那樣。 為了得到結果,我們監聽 3 個事件,

  • message响应工作线程发出消息。
  • exit工作线程停止执行的情况下触发的事件。
  • error发生错误时触发。

我们在最后一行main.js

console.log("Execution in main thread");
登入後複製

通过控制台的输出可得,主线程并没有被斐波那契数列运算执行而阻塞。

因此,只要在工作线程中处理 CPU 密集型任务,我们就可以继续处理其他任务而不必担心阻塞主线程。

结论

Node.js 在处理 CPU 密集型任务时一直因其性能而受到批评。通过有效地解决这些缺点,工作线程的引入提高了 Node.js 的功能。

有关worker_threads的更多信息,请在此处访问其官方文档。

思考

文章结束前留下思考,后续会在评论区做补充,欢迎一起讨论。

  • worker_threads线程空闲时候会被回收吗?
  • worker_threads共享内存如何使用?
  • 既然说到线程,那么应该有线程池?

更多node相关知识,请访问:nodejs 教程

以上是聊聊Node.js + worker_threads如何實作多執行緒? (詳解)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

C++ 函式異常與多執行緒:並發環境下的錯誤處理 C++ 函式異常與多執行緒:並發環境下的錯誤處理 May 04, 2024 pm 04:42 PM

C++中函數異常處理對於多執行緒環境特別重要,以確保執行緒安全性和資料完整性。透過try-catch語句,可以在出現異常時擷取和處理特定類型的異常,以防止程式崩潰或資料損壞。

PHP 多執行緒如何實作? PHP 多執行緒如何實作? May 06, 2024 pm 09:54 PM

PHP多執行緒是指在一個行程中同時執行多個任務,透過建立獨立運行的執行緒實作。 PHP中可以使用Pthreads擴充模擬多執行緒行為,安裝後可使用Thread類別建立和啟動執行緒。例如,處理大量資料時,可將資料分割為多個區塊,並建立對應數量的執行緒同時處理,提高效率。

Java函數的並發和多執行緒如何提高效能? Java函數的並發和多執行緒如何提高效能? Apr 26, 2024 pm 04:15 PM

使用Java函數的並發和多執行緒技術可以提升應用程式效能,包括以下步驟:理解並發和多執行緒概念。利用Java的並發和多執行緒函式庫,如ExecutorService和Callable。實作多執行緒矩陣乘法等案例,大幅縮短執行時間。享受並發和多執行緒帶來的應用程式響應速度提升和處理效率優化等優勢。

JUnit單元測試框架在多執行緒環境中的用法 JUnit單元測試框架在多執行緒環境中的用法 Apr 18, 2024 pm 03:12 PM

在多執行緒環境中使用JUnit時,有兩種常見方法:單執行緒測試和多執行緒測試。單執行緒測試在主執行緒上運行,避免並發問題,而多執行緒測試在工作執行緒上運行,需要同步測試方法來確保共享資源不受干擾。常見使用案例包括測試多執行緒安全方法,例如使用ConcurrentHashMap儲存鍵值對,並發執行緒對鍵值對進行操作並驗證其正確性,體現了多執行緒環境中JUnit的應用。

PHP 函數在多執行緒環境中的行為如何? PHP 函數在多執行緒環境中的行為如何? Apr 16, 2024 am 10:48 AM

在多執行緒環境中,PHP函數的行為取決於其類型:普通函數:執行緒安全,可並發執行。修改全域變數的函數:不安全,需使用同步機制。文件操作函數:不安全,需使用同步機制協調存取。資料庫操作函數:不安全,需使用資料庫系統機制防止衝突。

C++中如何處理多執行緒中的共享資源? C++中如何處理多執行緒中的共享資源? Jun 03, 2024 am 10:28 AM

C++中使用互斥量(mutex)處理多執行緒共享資源:透過std::mutex建立互斥量。使用mtx.lock()取得互斥量,對共享資源進行排他存取。使用mtx.unlock()釋放互斥。

C++ 記憶體管理在多執行緒環境中的挑戰與應對措施? C++ 記憶體管理在多執行緒環境中的挑戰與應對措施? Jun 05, 2024 pm 01:08 PM

在多執行緒環境中,C++記憶體管理面臨以下挑戰:資料競爭、死鎖和記憶體洩漏。因應措施包括:1.使用同步機制,如互斥鎖和原子變數;2.使用無鎖資料結構;3.使用智慧指標;4.(可選)實現垃圾回收。

C++ 多執行緒程式測試的挑戰與策略 C++ 多執行緒程式測試的挑戰與策略 May 31, 2024 pm 06:34 PM

多執行緒程式測試面臨不可重複性、並發錯誤、死鎖和缺乏可視性等挑戰。策略包括:單元測試:針對每個執行緒編寫單元測試,驗證執行緒行為。多執行緒模擬:使用模擬框架在控制執行緒調度的情況下測試程式。資料競態偵測:使用工具尋找潛在的資料競態,如valgrind。調試:使用調試器(如gdb)檢查運行時程序狀態,找到資料競爭根源。

See all articles