首頁 web前端 js教程 JavaScript中的Web worker多執行緒API研究_javascript技巧

JavaScript中的Web worker多執行緒API研究_javascript技巧

May 16, 2016 pm 04:28 PM
api javascript web worker 多執行緒

HTML5支援了Web Worker這樣的API,允許網頁在安全的情況下執行多執行緒程式碼。不過Web Worker其實受到很多限制,因為它無法真正意義上共享記憶體數據,只能透過訊息來做狀態通知,所以甚至不能稱之為真正意義上的「多執行緒」。

Web Worker的介面使用起來很不方便,它基本上自備一個sandbox,在沙箱中跑一個獨立的js文件,透過 postMessage和 onMessge來和主執行緒通訊:

複製程式碼 程式碼如下:

var worker = new Worker("my.js");
var bundle = {message:'Hello world', id:1};
worker.postMessage(bundle); //postMessage可以傳送一個可序列化的物件過去
worker.onmessage = function(evt){
    console.log(evt.data);    //比較worker中傳回的物件和主執行緒中的物件
    console.log(bundle);  //{message:'Hello world', id:1}
}

複製程式碼 程式碼如下:

//in my.js
onmessage = function(evt){
    var data = evt.data;
    data.id ;
    postMessage(data); //{message:'Hello world', id:2}
}

得到的結果可以發現,線程中得到的data的id增加了,但是傳回來之後,並沒有改變主線程的bundle中的id,因此,線程中傳遞的對象實際上copy了一份,這樣的話,線程並沒有共享數據,避免了讀寫衝突,所以是安全的。保證線程安全的代價就是限制了在線程中操作主線程物件的能力。

這樣一個有限的多執行緒機制使用起來是很不方便的,我們當然希望Worker能夠支援讓程式碼看起來具有同時操作多執行緒的能力,例如,支援看起來像下面這個樣子的程式碼:

複製程式碼 程式碼如下:

var worker = new ThreadWorker(bundle /*shared obj*/);

worker.run(function(bundle){
    //do sth in worker thread...
    this.runOnUiThread(function(bundle /*shared obj*/){
        //do sth in main ui thread...
    });
    //...
});

這段程式碼裡面,我們啟動一個worker之後,能夠讓任意程式碼跑在worker中,並且當需要操作ui執行緒(例如讀寫dom)時,可以透過this.runOnUiThread回到主執行緒執行。

那麼如何實現這個機制呢? 看下面的程式碼:

複製程式碼 程式碼如下:

function WorkerThread(sharedObj){
    this._worker = new Worker("thread.js");
    this._completes = {};
    this._task_id = 0;
    this.sharedObj = sharedObj;

    var self = this;
    this._worker.onmessage = function(evt){
        var ret = evt.data;
        if(ret.__UI_TASK__){
            //run on ui task
            var fn = (new Function("return " ret.__UI_TASK__))();
            fn(ret.sharedObj);
        }else{
            self.sharedObj = ret.sharedObj;
            self._completes[ret.taskId](ret);
        }
    }
}

WorkerThread.prototype.run = function(task, complete){
    var _task = {__THREAD_TASK__:task.toString(), sharedObj: this.sharedObj, taskId: this._task_id};
    this._completes[this._task_id ] = complete;
    this._worker.postMessage(_task);
}

上面這段程式碼定義了一個ThreadWorker對象,這個物件建立了一個執行thread.js的Web Worker,保存了共享對象SharedObj,並且對thread.js發回的訊息進行處理。

如果thread.js中傳回了一個UI_TASK訊息,那麼執行這個訊息傳過來的function,否則執行run的complete回呼 我們看看thread.js是怎麼寫的:

複製程式碼 程式碼如下:

onmessage = function(evt){
    var data = evt.data;

    if(data && data.__THREAD_TASK__){
        var task = data.__THREAD_TASK__;
        try{
            var fn = (new Function("return " task))();

            var ctx = {
                threadSignal: true,
                sleep: function(interval){
                    ctx.threadSignal = false;
                    setTimeout(_run, interval);
                },
                runOnUiThread: function(task){
                    postMessage({__UI_TASK__:task.toString(), sharedObj:data.sharedObj});
                }
            }

            function _run(){
                ctx.threadSignal = true;
                var ret = fn.call(ctx, data.sharedObj);
                postMessage({error:null, returnValue:ret, __THREAD_TASK__:task, sharedObj:data.sharedObj, taskId: data.taskId: data.taskId: data.             }

            _run(0);

        }catch(ex){

            postMessage({error:ex.toString() , returnValue:null, sharedObj: data.sharedObj});
        }
    }
}

可以看到,thread.js接收ui線程傳過來的消息,其中最重要的是THREAD_TASK,這是ui線程傳過來的需要worker線程執行的“任務”,由於function是不可序列化的,因此傳遞的是字串,worker執行緒透過解析字串成function來執行主執行緒提交的任務(注意在任務中將共享物件sharedObj傳入),執行完成後將返回結果透過message傳給ui執行緒。我們仔細看一下除了返回值returnValue以外,共享對象sharedObj也會被傳回,傳回時,由於worker線程和ui線程並不共享對象,因此我們人為通過賦值的方式同步兩邊的對象(這樣是否線程安全?

可以看到整個過程其實並不複雜,這麼實作之後,這個ThreadWorker可以有以下兩種用法:

複製程式碼 程式碼如下:

var t1 = new WorkerThread({i: 100} /*共用物件*/);

        setInterval(function(){
            t1.run(函數(sharedObj){
                    返回sharedObj.i;
                },
                函數(r){
                    console.log("t1>" r.returnValue ":" r.error);
                }
            );
        }, 500);
var t2 = new WorkerThread({i: 50});

        t2.run(function(sharedObj){  
            while(this.threadSignal){
                共享物件.i ;

                this.runOnUiThread(function(sharedObj){
                    W("body ul").appendChild("

  • " shareObj.i "
  • ");
                    });

                    this.sleep(500);
                }
                返回sharedObj.i;
            }, 函數(r){
                console.log("t2>" r.returnValue ":" r.error);
            });

    這樣的方式從形式和語意上來說都讓其具有良好的結構、靈活和可程式化。

    好了,關於Web Worker的探討就介紹到這裡了,有興趣的同學可以看看這個專案:https://github.com/akira-cn/WorkerThread.js (由於Worker需要用伺服器測試,我特意在專案中放了一個山寨的httpd.js,是個很簡陋的http服務的js,直接用node就可以跑起來)。

    本網站聲明
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡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的應用。

    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)檢查運行時程序狀態,找到資料競爭根源。

    C++ 技術中的例外處理:如何在多執行緒環境中正確處理例外狀況? C++ 技術中的例外處理:如何在多執行緒環境中正確處理例外狀況? May 09, 2024 pm 12:36 PM

    在多執行緒C++中,例外處理遵循以下原則:及時性、執行緒安全性和明確性。在實戰中,可以透過使用mutex或原子變數來確保異常處理程式碼線程安全。此外,還要考慮異常處理程式碼的重入性、效能和測試,以確保其在多執行緒環境中安全有效地運作。

    See all articles