Node.js+worker_threads怎么實(shí)現(xiàn)多線程

這篇文章主要介紹“Node.js + worker_threads怎么實(shí)現(xiàn)多線程”的相關(guān)知識(shí),小編通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“Node.js + worker_threads怎么實(shí)現(xiàn)多線程”文章能幫助大家解決問(wèn)題。

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶,將通過(guò)不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:域名申請(qǐng)、網(wǎng)絡(luò)空間、營(yíng)銷(xiāo)軟件、網(wǎng)站建設(shè)、銅陵網(wǎng)站維護(hù)、網(wǎng)站推廣。

Node.js + worker_threads怎么實(shí)現(xiàn)多線程

通常情況下,Node.js被認(rèn)為是單線程。由主線程去按照編碼順序一步步執(zhí)行程序代碼,一旦遇到同步代碼阻塞,主線程就會(huì)被占用,后續(xù)的程序代碼的執(zhí)行都會(huì)被卡住。沒(méi)錯(cuò)Node.js的單線程指的是主線程是"單線程"。

為了解決單線程帶來(lái)的問(wèn)題,本文的主角worker_threads出現(xiàn)了。worker_threads首次在Node.js v10.5.0作為實(shí)驗(yàn)性功能出現(xiàn),需要命令行帶上--experimental-worker才能使用。直到v12.11.0穩(wěn)定版才能正式使用。

本文將會(huì)介紹worker_threads的使用方式,以及利用worker_threads執(zhí)行斐波那契數(shù)列作為實(shí)踐例子。

先決條件

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

  • 安裝了 Node.js v12.11.0 及以上版本

  • 掌握 JavaScript 同步和異步編程的基礎(chǔ)知識(shí)

  • 掌握 Node.js 的工作原理

worker_threads 介紹

worker_threads 模塊允許使用并行執(zhí)行 JavaScript 的線程。

工作線程對(duì)于執(zhí)行 CPU 密集型的 JavaScript 操作很有用。 它們對(duì) I/O 密集型的工作幫助不大。 Node.js 內(nèi)置的異步 I/O 操作比工作線程更高效。

child_processcluster 不同,worker_threads 可以共享內(nèi)存。 它們通過(guò)傳輸 ArrayBuffer 實(shí)例或共享 SharedArrayBuffer 實(shí)例來(lái)實(shí)現(xiàn)。

由于以下特性,worker_threads已被證明是充分利用CPU性能的最佳解決方案:

  • 它們運(yùn)行具有多個(gè)線程的單個(gè)進(jìn)程。

  • 每個(gè)線程執(zhí)行一個(gè)事件循環(huán)。

  • 每個(gè)線程運(yùn)行單個(gè) JS 引擎實(shí)例。

  • 每個(gè)線程執(zhí)行單個(gè) Nodejs 實(shí)例。

worker_threads 如何工作

worker_threads通過(guò)執(zhí)行主線程指定的腳本文件來(lái)工作。每個(gè)線程都在與其他線程隔離的情況下執(zhí)行。但是,這些線程可以通過(guò)消息通道來(lái)回傳遞消息。

主線程使用worker.postMessage()函數(shù)使用消息通道,而工作線程使用parentPort.postMessage()函數(shù)。

通過(guò)官方示例代碼加強(qiáng)了解:

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));
}

上述代碼主線程工作線程都使用同一份文件作為執(zhí)行腳本(__filename為當(dāng)前執(zhí)行文件路徑),通過(guò)isMainThread來(lái)區(qū)分主線程工作線程運(yùn)行時(shí)邏輯。當(dāng)模塊對(duì)外暴露方法parseJSAsync被調(diào)用時(shí)候,都將會(huì)衍生子工作線程去執(zhí)行調(diào)用parse函數(shù)。

worker_threads 具體使用

在本節(jié)使用具體例子介紹worker_threads的使用

創(chuàng)建工作線程腳本文件workerExample.js:

const { workerData, parentPort } = require('worker_threads')
parentPort.postMessage({ welcome: workerData })

創(chuàng)建主線程腳本文件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))

控制臺(tái)命令行執(zhí)行:

node main.js

輸出:

{ welcome: 'hello worker threads' }

worker_threads 運(yùn)算斐波那契數(shù)列

在本節(jié)中,讓我們看一下 CPU 密集型示例,生成斐波那契數(shù)列。

如果在沒(méi)有工作線程的情況下完成此任務(wù),則會(huì)隨著nth期限的增加而阻塞主線程。

創(chuàng)建工作線程腳本文件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);
    }
}

創(chuàng)建主線程腳本文件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");

控制臺(tái)命令行執(zhí)行:

node main.js

輸出:

Execution in main thread
30th Fibonacci Result: 832040
It exited with code 0

main.js文件中,我們從類(lèi)的實(shí)例創(chuàng)建一個(gè)工作線程,Worker正如我們?cè)谇懊娴氖纠锌吹降哪菢印?/p>

為了得到結(jié)果,我們監(jiān)聽(tīng) 3 個(gè)事件,

  • message響應(yīng)工作線程發(fā)出消息。

  • exit工作線程停止執(zhí)行的情況下觸發(fā)的事件。

  • error發(fā)生錯(cuò)誤時(shí)觸發(fā)。

我們?cè)谧詈笠恍?code>main.js,

console.log("Execution in main thread");

通過(guò)控制臺(tái)的輸出可得,主線程并沒(méi)有被斐波那契數(shù)列運(yùn)算執(zhí)行而阻塞。

因此,只要在工作線程中處理 CPU 密集型任務(wù),我們就可以繼續(xù)處理其他任務(wù)而不必?fù)?dān)心阻塞主線程。

關(guān)于“Node.js + worker_threads怎么實(shí)現(xiàn)多線程”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

分享名稱(chēng):Node.js+worker_threads怎么實(shí)現(xiàn)多線程
文章轉(zhuǎn)載:http://bm7419.com/article44/jcscee.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供手機(jī)網(wǎng)站建設(shè)、企業(yè)網(wǎng)站制作、網(wǎng)站設(shè)計(jì)公司、網(wǎng)站內(nèi)鏈、移動(dòng)網(wǎng)站建設(shè)、用戶體驗(yàn)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司