• <sub id="h4knl"><ol id="h4knl"></ol></sub>
    <sup id="h4knl"></sup>
      <sub id="h4knl"></sub>

      <sub id="h4knl"><ol id="h4knl"><em id="h4knl"></em></ol></sub><s id="h4knl"></s>
      1. <strong id="h4knl"></strong>

      2. 深入理解JavaScript中的并行處理的介紹

        時(shí)間:2024-10-14 00:52:53 JavaScript 我要投稿
        • 相關(guān)推薦

        有關(guān)深入理解JavaScript中的并行處理的介紹

          前言

          為什么說多線程如此重要?這是個(gè)值得思考的問題。一直以來,派生線程以一種優(yōu)雅的方式實(shí)現(xiàn)了對同一個(gè)進(jìn)程中任務(wù)的劃分。操作系統(tǒng)負(fù)責(zé)分配每個(gè)線程的時(shí)間片,具有高優(yōu)先級并且任務(wù)繁重的線程將分配到更多的時(shí)間片,而低優(yōu)先級空閑的線程只能分到較少的時(shí)間片。

          雖然多線程如此重要,但JavaScript卻并沒有多線程的能力。幸運(yùn)的是,隨著 Web Worker 的普及,我們終于可以在后臺(tái)線程來處理資源密集型的計(jì)算了。而不好的方面是,目前制定的標(biāo)準(zhǔn)只適用于當(dāng)前的生態(tài)系統(tǒng),這有時(shí)候就比較尷尬了。如果你了解其他從一開始就支持多線程的語言的話,你可能會(huì)發(fā)現(xiàn)很多的限制,遠(yuǎn)非僅僅是實(shí)例化一個(gè)新線程,然后你操控這個(gè)實(shí)例就能實(shí)現(xiàn)多線程。

          這篇文章主要來介紹 Web Worker,包括什么時(shí)候使用,該怎么使用,它有什么奇怪的特性,會(huì)介紹在 Webpack 中如何使用它,還有可能遇到的一些坑。

          一、Web Workers

          Web Worker 可能是在 JavaScript 中唯一可以真正實(shí)現(xiàn)多線程的方法了。我們需要按照下面的方式創(chuàng)建 worker :

          const worker = newWorker("worker.js");

          上面就定義了一個(gè) Worker 實(shí)例,然后你可以通過 postMessage 與 worker 通信,就像和 iFrame 通信一樣,只不過不存在跨域的問題,不需要驗(yàn)證跨域。

          worker.postMessage(num);

          在 worker 代碼中,你需要監(jiān)聽這些事件:

          onmessage = (e) => { // e.data will contain the value passed};

          這種方式是雙向的,所以你也可以從 worker 中 postMessage 給我們的主程序。

          在 worker 代碼中:

          postMessage(result);

          在主程序中:

          worker.onmessage = (e) => {}

          這就是 worker 最基本的用法。

          異常處理

          在你的 worker 代碼中,有很多種方式來處理異常,比如你可以 catch 之后通過 postMessage 傳遞,這樣可能需要多些一些代碼,但是確實(shí)最有效也最安全的。

          另一種方式是用 onerror 事件,這種方式可以捕捉所有未處理的異常,并且交給調(diào)用方來決定如何處理。調(diào)用方式很簡單:

          worker.onerror = (e) => {};

          為了調(diào)試方便,異常對象中還有一些額外的字段比如:filename,lineno,colno.

          回收

          將不需要的 worker 回收是非常重要的,worker 會(huì)生成真正的操作系統(tǒng)線程,如果你發(fā)現(xiàn)與很多 worker 線程同時(shí)運(yùn)行,你可以通過很簡單的殺掉瀏覽器進(jìn)程。

          你有兩種方式殺掉 worker 進(jìn)程:在 worker 里和在 worker 外。我認(rèn)為最好的處理 worker 生命周期的地方是在主頁面里,但這也要取決于你代碼的具體情況。

          殺掉一個(gè) worker 實(shí)例,在外部可以直接調(diào)用 terminate()方法,這種方法可以立即殺掉它,釋放所有它正在使用的資源,如果它正在運(yùn)行,也會(huì)立即終止。

          如果你想要讓 worker 自己去管理它的生命周期,可以直接在 worker 代碼中調(diào)用stop()方法。

          不管使用哪種方法,worker 都會(huì)停止,銷毀所有資源。

          如果你想使用一種“一次性”的 worker,比如需要做一些復(fù)雜運(yùn)算之后就不再使用了,也要確保在 onerror 事件中去銷毀它們,這樣有利于規(guī)避一些難以發(fā)現(xiàn)的問題。

          worker.onerror = (e) => { worker.terminate(); reject(e);};worker.onmessage = (e) => { worker.terminate(); resolve(e.data);}

          二、行內(nèi) Workers

          有些時(shí)候?qū)?worker 代碼寫到一個(gè)外部文件可能會(huì)使原本簡單的問題變得復(fù)雜,幸運(yùn)的是,workers 也可以用一個(gè) Blob 來初始化。

          寫一個(gè)行內(nèi) worker ,參考如下代碼段:

          // Put your worker code here

          const code = URL.createObjectURL(new Blob([ document.getElementById("worker").textContent]));const worker = new Worker(code);

          這樣你就創(chuàng)建了一個(gè)全局的 ObjectURL,但別忘了當(dāng)不需要的時(shí)候要銷毀它:

          worker.terminate();URL.revokeObjectURL(code);

          三、Workers 嵌套

          理論上,你可以嵌套使用 worker,就像在主線程中定義一個(gè) worker 一樣。這里有一個(gè)簡單的 例子。但是不幸的是在 Chrome 中一直存在一個(gè) bug ,讓我們不能愉快的玩耍,或許以后這個(gè) bug 會(huì)修復(fù),但是目前來說還是沒有太多進(jìn)展,所以你最好不要使用。

          數(shù)據(jù)傳遞

          在 worker 數(shù)據(jù)傳遞的過程中有些需要注意的邊緣情況。你可以傳遞數(shù)值,字符串,數(shù)組,也可以傳遞序列化/反序列化的對象。然而,你卻不應(yīng)該依賴序列化來保持?jǐn)?shù)據(jù)結(jié)構(gòu),實(shí)際上,postMessage 用到了一種 數(shù)據(jù)克隆算法,它會(huì)生成一些額外的屬性比如 RegExps 和 Blobs 以及一些循環(huán)引用。

          這就是說,你需要將你要傳遞的數(shù)據(jù)最小化。你不可以傳遞 functions ,即使是支持的類型也會(huì)有一些限制,這些也很容易產(chǎn)生一些難以發(fā)現(xiàn)的 bug。如果你將你的 API 定義為只傳遞字符串,數(shù)值,數(shù)組和對象的話,那你可能會(huì)避過這些問題。

          循環(huán)引用

          如果你有一個(gè)很復(fù)雜的對象,那么里面很可能存在循環(huán)引用,這時(shí)如果你將它序列化成 JSON,你將會(huì)得到一個(gè) TypeError: Converting circular structure to JSON.

          let a = {};let b = {a};a.b = b;JSON.stringify({a,b}); // Error

          然而你可以在 postMessage 中放心的使用,從而你就可以在 worker 中使用。

          Transferable objects

          為了防止同時(shí)修改同一變量的場景,你傳遞給 postMessage 的所有變量都會(huì)復(fù)制一份,這樣確保了你多個(gè)線程不會(huì)修改同一個(gè)變量。但如果你想要傳一個(gè)非常大的數(shù)據(jù)的話,你就會(huì)發(fā)現(xiàn)復(fù)制操作是很慢的。比如,如果你在做一些圖片相關(guān)的運(yùn)算,你可能會(huì)傳遞整個(gè)圖片信息,就可能會(huì)遇到復(fù)制性能的瓶頸。

          好在有 transferable object ,用 transfer 來代替 copy,比如ArrayBuffer 是transferable對象,而我們可以把任何類型的對象放在 ArrayBuffer 中。

          如果你 transfer 一個(gè)對象,之前擁有它的線程被鎖定權(quán)限,它確保了數(shù)據(jù)沒有復(fù)制之前,不會(huì)被同時(shí)修改。

          這時(shí) postMessage 的代碼段就有點(diǎn)尷尬了:

          const ab = new ArrayBuffer(100);console.log(ab.byteLength); // 100worker.postMessage(ab, [ab]);console.log(ab.byteLength); // 0

          確保在 postMessage 中傳遞第二個(gè)參數(shù),否則數(shù)據(jù)將會(huì)被復(fù)制。

          const ab = new ArrayBuffer(100);console.log(ab.byteLength); // 100worker.postMessage(ab);console.log(ab.byteLength); // 100

          四、Webpack

          在 Webpack 中使用 Web worker 時(shí),你需要用 worker-loader。將它添加到 package.json 中的 devDependencies,然后運(yùn)行 npm install,就可以了。

          用到 worker 時(shí),只需要 require 它。

          const workerCode = require("worker!./worker.js");...const worker = new workerCode();

          這樣就初始化了 worker,然后就像上面講的一樣使用 worker。

          如果需要使用行內(nèi) worker,你需要傳遞 inline 參數(shù)給 loader。

          const workerCode = require("worker?inline!./worker.js");...const worker = new workerCode();

          在 worker 中你也可以 import 模塊。

          import fibonacci from "./fibonacci.js";...const result = fibonacci(num);

          缺點(diǎn)

          在 Webpack 中使用 worker 很簡單,但是在使用時(shí)也有一些坑值得你注意。

          首先,無法將代碼共用部分提取出來。如果你的 worker 中依賴一段共用代碼,你只能把代碼添加到 worker 中,不管其他地方是否也用到同樣的代碼。而且如果你多個(gè) worker 要用同樣的庫,你也需要在每個(gè) worker 中引入它們。

          你可能會(huì)想如果你不用 worker-loader,然后用CommonsChunkPlugin指定一個(gè)新的入口,可能會(huì)解決這個(gè)問題。但是不幸的是 worker 不像是瀏覽器 window ,一些 feature 不可用,所以一些代碼必須要引入。

          同時(shí),用行內(nèi) worker 也不會(huì)解決問題,共用的代碼依然會(huì)出現(xiàn)在多個(gè)地方。

          第二點(diǎn)缺點(diǎn)是,行內(nèi) worker 可能會(huì)導(dǎo)致 ObjectURLs內(nèi)存泄露.它們被創(chuàng)建出來以后就不會(huì)被釋放。這雖然不是一個(gè)大問題,但是如果你有很多“一次性” worker 的話,就會(huì)影響性能。

          綜上所述,我個(gè)人建議是使用標(biāo)準(zhǔn)的 worker,注意在 worker 中引入了什么。還要注意使用緩存。

          五、IFrames Web worker

          IFrames Web worker 和 IFrame 很像,而且印象中 IFrame 也可以實(shí)現(xiàn)多線程。但是 IFrame 存在一些不是線程安全 API,比如 DOM 相關(guān),瀏覽器不能為他們生成新的線程,參考這里.

          在 IFrame 跨域中,很多 API 它都沒有權(quán)限,也只能通過 postMessage,就像 Web Worker 一樣。理論上,瀏覽器可以在不同的線程中運(yùn)行 IFrame,也就可以用 IFrame 實(shí)現(xiàn)多線程。

          但是實(shí)際并非如此,它還是單線程的,瀏覽器不會(huì)給它們額外的線程。

          總結(jié)

          Web Worker 解決了 JavaScript 一直以來的大難題,盡管它的語法有些奇怪而且有很多限制,但是它卻可以真真正正的解決問題。從另外一方面來講,它也還是個(gè)嬰兒,某些方面還不是很成熟,不能讓我們完全依賴,所以這個(gè)技術(shù)普及還有一段距離,目前適用場景也比較局限。所以說,如果你需要做多線程,不要再等待其他的什么技術(shù),學(xué)習(xí) web worker 的邊緣問題,避開它的坑,你就可以很好的提高用戶體驗(yàn)。以上就是這篇文章的全部內(nèi)容,希望對大家能有所幫助。

        《&.doc》
        将本文的Word文档下载到电脑,方便收藏和打印
        推荐度:
        点击下载文档

        【深入理解JavaScript中的并行處理的介紹】相關(guān)文章:

        對javascript的理解03-29

        淺談javascript中的單線程理解03-30

        淺談如何深入學(xué)習(xí)Javascript中的this關(guān)鍵字04-02

        理解JavaScript原型鏈教程03-30

        javascript編程異常處理的方法03-31

        javascript的閉包概念怎么理解03-29

        在Java中執(zhí)行JavaScript代碼04-01

        Javascript中typeof 用法歸納04-01

        在线咨询
        国产高潮无套免费视频_久久九九兔免费精品6_99精品热6080YY久久_国产91久久久久久无码
      3. <sub id="h4knl"><ol id="h4knl"></ol></sub>
        <sup id="h4knl"></sup>
          <sub id="h4knl"></sub>

          <sub id="h4knl"><ol id="h4knl"><em id="h4knl"></em></ol></sub><s id="h4knl"></s>
          1. <strong id="h4knl"></strong>

          2. 中文字一区二区三区在线 | 亚洲国产欧美另类专区 | 亚洲精品视频福利 | 综合视频精品第一区 | 天天摸天天碰天天添中文字幕 | 无遮高潮国产免费观看 |

            有關(guān)深入理解JavaScript中的并行處理的介紹

              前言

              為什么說多線程如此重要?這是個(gè)值得思考的問題。一直以來,派生線程以一種優(yōu)雅的方式實(shí)現(xiàn)了對同一個(gè)進(jìn)程中任務(wù)的劃分。操作系統(tǒng)負(fù)責(zé)分配每個(gè)線程的時(shí)間片,具有高優(yōu)先級并且任務(wù)繁重的線程將分配到更多的時(shí)間片,而低優(yōu)先級空閑的線程只能分到較少的時(shí)間片。

              雖然多線程如此重要,但JavaScript卻并沒有多線程的能力。幸運(yùn)的是,隨著 Web Worker 的普及,我們終于可以在后臺(tái)線程來處理資源密集型的計(jì)算了。而不好的方面是,目前制定的標(biāo)準(zhǔn)只適用于當(dāng)前的生態(tài)系統(tǒng),這有時(shí)候就比較尷尬了。如果你了解其他從一開始就支持多線程的語言的話,你可能會(huì)發(fā)現(xiàn)很多的限制,遠(yuǎn)非僅僅是實(shí)例化一個(gè)新線程,然后你操控這個(gè)實(shí)例就能實(shí)現(xiàn)多線程。

              這篇文章主要來介紹 Web Worker,包括什么時(shí)候使用,該怎么使用,它有什么奇怪的特性,會(huì)介紹在 Webpack 中如何使用它,還有可能遇到的一些坑。

              一、Web Workers

              Web Worker 可能是在 JavaScript 中唯一可以真正實(shí)現(xiàn)多線程的方法了。我們需要按照下面的方式創(chuàng)建 worker :

              const worker = newWorker("worker.js");

              上面就定義了一個(gè) Worker 實(shí)例,然后你可以通過 postMessage 與 worker 通信,就像和 iFrame 通信一樣,只不過不存在跨域的問題,不需要驗(yàn)證跨域。

              worker.postMessage(num);

              在 worker 代碼中,你需要監(jiān)聽這些事件:

              onmessage = (e) => { // e.data will contain the value passed};

              這種方式是雙向的,所以你也可以從 worker 中 postMessage 給我們的主程序。

              在 worker 代碼中:

              postMessage(result);

              在主程序中:

              worker.onmessage = (e) => {}

              這就是 worker 最基本的用法。

              異常處理

              在你的 worker 代碼中,有很多種方式來處理異常,比如你可以 catch 之后通過 postMessage 傳遞,這樣可能需要多些一些代碼,但是確實(shí)最有效也最安全的。

              另一種方式是用 onerror 事件,這種方式可以捕捉所有未處理的異常,并且交給調(diào)用方來決定如何處理。調(diào)用方式很簡單:

              worker.onerror = (e) => {};

              為了調(diào)試方便,異常對象中還有一些額外的字段比如:filename,lineno,colno.

              回收

              將不需要的 worker 回收是非常重要的,worker 會(huì)生成真正的操作系統(tǒng)線程,如果你發(fā)現(xiàn)與很多 worker 線程同時(shí)運(yùn)行,你可以通過很簡單的殺掉瀏覽器進(jìn)程。

              你有兩種方式殺掉 worker 進(jìn)程:在 worker 里和在 worker 外。我認(rèn)為最好的處理 worker 生命周期的地方是在主頁面里,但這也要取決于你代碼的具體情況。

              殺掉一個(gè) worker 實(shí)例,在外部可以直接調(diào)用 terminate()方法,這種方法可以立即殺掉它,釋放所有它正在使用的資源,如果它正在運(yùn)行,也會(huì)立即終止。

              如果你想要讓 worker 自己去管理它的生命周期,可以直接在 worker 代碼中調(diào)用stop()方法。

              不管使用哪種方法,worker 都會(huì)停止,銷毀所有資源。

              如果你想使用一種“一次性”的 worker,比如需要做一些復(fù)雜運(yùn)算之后就不再使用了,也要確保在 onerror 事件中去銷毀它們,這樣有利于規(guī)避一些難以發(fā)現(xiàn)的問題。

              worker.onerror = (e) => { worker.terminate(); reject(e);};worker.onmessage = (e) => { worker.terminate(); resolve(e.data);}

              二、行內(nèi) Workers

              有些時(shí)候?qū)?worker 代碼寫到一個(gè)外部文件可能會(huì)使原本簡單的問題變得復(fù)雜,幸運(yùn)的是,workers 也可以用一個(gè) Blob 來初始化。

              寫一個(gè)行內(nèi) worker ,參考如下代碼段:

              // Put your worker code here

              const code = URL.createObjectURL(new Blob([ document.getElementById("worker").textContent]));const worker = new Worker(code);

              這樣你就創(chuàng)建了一個(gè)全局的 ObjectURL,但別忘了當(dāng)不需要的時(shí)候要銷毀它:

              worker.terminate();URL.revokeObjectURL(code);

              三、Workers 嵌套

              理論上,你可以嵌套使用 worker,就像在主線程中定義一個(gè) worker 一樣。這里有一個(gè)簡單的 例子。但是不幸的是在 Chrome 中一直存在一個(gè) bug ,讓我們不能愉快的玩耍,或許以后這個(gè) bug 會(huì)修復(fù),但是目前來說還是沒有太多進(jìn)展,所以你最好不要使用。

              數(shù)據(jù)傳遞

              在 worker 數(shù)據(jù)傳遞的過程中有些需要注意的邊緣情況。你可以傳遞數(shù)值,字符串,數(shù)組,也可以傳遞序列化/反序列化的對象。然而,你卻不應(yīng)該依賴序列化來保持?jǐn)?shù)據(jù)結(jié)構(gòu),實(shí)際上,postMessage 用到了一種 數(shù)據(jù)克隆算法,它會(huì)生成一些額外的屬性比如 RegExps 和 Blobs 以及一些循環(huán)引用。

              這就是說,你需要將你要傳遞的數(shù)據(jù)最小化。你不可以傳遞 functions ,即使是支持的類型也會(huì)有一些限制,這些也很容易產(chǎn)生一些難以發(fā)現(xiàn)的 bug。如果你將你的 API 定義為只傳遞字符串,數(shù)值,數(shù)組和對象的話,那你可能會(huì)避過這些問題。

              循環(huán)引用

              如果你有一個(gè)很復(fù)雜的對象,那么里面很可能存在循環(huán)引用,這時(shí)如果你將它序列化成 JSON,你將會(huì)得到一個(gè) TypeError: Converting circular structure to JSON.

              let a = {};let b = {a};a.b = b;JSON.stringify({a,b}); // Error

              然而你可以在 postMessage 中放心的使用,從而你就可以在 worker 中使用。

              Transferable objects

              為了防止同時(shí)修改同一變量的場景,你傳遞給 postMessage 的所有變量都會(huì)復(fù)制一份,這樣確保了你多個(gè)線程不會(huì)修改同一個(gè)變量。但如果你想要傳一個(gè)非常大的數(shù)據(jù)的話,你就會(huì)發(fā)現(xiàn)復(fù)制操作是很慢的。比如,如果你在做一些圖片相關(guān)的運(yùn)算,你可能會(huì)傳遞整個(gè)圖片信息,就可能會(huì)遇到復(fù)制性能的瓶頸。

              好在有 transferable object ,用 transfer 來代替 copy,比如ArrayBuffer 是transferable對象,而我們可以把任何類型的對象放在 ArrayBuffer 中。

              如果你 transfer 一個(gè)對象,之前擁有它的線程被鎖定權(quán)限,它確保了數(shù)據(jù)沒有復(fù)制之前,不會(huì)被同時(shí)修改。

              這時(shí) postMessage 的代碼段就有點(diǎn)尷尬了:

              const ab = new ArrayBuffer(100);console.log(ab.byteLength); // 100worker.postMessage(ab, [ab]);console.log(ab.byteLength); // 0

              確保在 postMessage 中傳遞第二個(gè)參數(shù),否則數(shù)據(jù)將會(huì)被復(fù)制。

              const ab = new ArrayBuffer(100);console.log(ab.byteLength); // 100worker.postMessage(ab);console.log(ab.byteLength); // 100

              四、Webpack

              在 Webpack 中使用 Web worker 時(shí),你需要用 worker-loader。將它添加到 package.json 中的 devDependencies,然后運(yùn)行 npm install,就可以了。

              用到 worker 時(shí),只需要 require 它。

              const workerCode = require("worker!./worker.js");...const worker = new workerCode();

              這樣就初始化了 worker,然后就像上面講的一樣使用 worker。

              如果需要使用行內(nèi) worker,你需要傳遞 inline 參數(shù)給 loader。

              const workerCode = require("worker?inline!./worker.js");...const worker = new workerCode();

              在 worker 中你也可以 import 模塊。

              import fibonacci from "./fibonacci.js";...const result = fibonacci(num);

              缺點(diǎn)

              在 Webpack 中使用 worker 很簡單,但是在使用時(shí)也有一些坑值得你注意。

              首先,無法將代碼共用部分提取出來。如果你的 worker 中依賴一段共用代碼,你只能把代碼添加到 worker 中,不管其他地方是否也用到同樣的代碼。而且如果你多個(gè) worker 要用同樣的庫,你也需要在每個(gè) worker 中引入它們。

              你可能會(huì)想如果你不用 worker-loader,然后用CommonsChunkPlugin指定一個(gè)新的入口,可能會(huì)解決這個(gè)問題。但是不幸的是 worker 不像是瀏覽器 window ,一些 feature 不可用,所以一些代碼必須要引入。

              同時(shí),用行內(nèi) worker 也不會(huì)解決問題,共用的代碼依然會(huì)出現(xiàn)在多個(gè)地方。

              第二點(diǎn)缺點(diǎn)是,行內(nèi) worker 可能會(huì)導(dǎo)致 ObjectURLs內(nèi)存泄露.它們被創(chuàng)建出來以后就不會(huì)被釋放。這雖然不是一個(gè)大問題,但是如果你有很多“一次性” worker 的話,就會(huì)影響性能。

              綜上所述,我個(gè)人建議是使用標(biāo)準(zhǔn)的 worker,注意在 worker 中引入了什么。還要注意使用緩存。

              五、IFrames Web worker

              IFrames Web worker 和 IFrame 很像,而且印象中 IFrame 也可以實(shí)現(xiàn)多線程。但是 IFrame 存在一些不是線程安全 API,比如 DOM 相關(guān),瀏覽器不能為他們生成新的線程,參考這里.

              在 IFrame 跨域中,很多 API 它都沒有權(quán)限,也只能通過 postMessage,就像 Web Worker 一樣。理論上,瀏覽器可以在不同的線程中運(yùn)行 IFrame,也就可以用 IFrame 實(shí)現(xiàn)多線程。

              但是實(shí)際并非如此,它還是單線程的,瀏覽器不會(huì)給它們額外的線程。

              總結(jié)

              Web Worker 解決了 JavaScript 一直以來的大難題,盡管它的語法有些奇怪而且有很多限制,但是它卻可以真真正正的解決問題。從另外一方面來講,它也還是個(gè)嬰兒,某些方面還不是很成熟,不能讓我們完全依賴,所以這個(gè)技術(shù)普及還有一段距離,目前適用場景也比較局限。所以說,如果你需要做多線程,不要再等待其他的什么技術(shù),學(xué)習(xí) web worker 的邊緣問題,避開它的坑,你就可以很好的提高用戶體驗(yàn)。以上就是這篇文章的全部內(nèi)容,希望對大家能有所幫助。