前端高效能運算之一:WebWorkers

發表於2017-10-21

最近做一個專案,裡面涉及到在前端做大量計算,直接用js跑了一下,大概需要15s的時間, 也就是使用者的瀏覽器會卡死15s,這個完全接受不了。

雖說有V8這樣牛逼的引擎,但大家知道js並不適合做CPU密集型的計算,一是因為單執行緒,二是因為動態語言。我們就從這兩個突破口入手,首先搞定“單執行緒”的限制,嘗試用WebWorkers來加速計算。

什麼是WebWorkers

簡單說,WebWorkers是一個HTML5的新API,web開發者可以通過此API在後臺執行一個指令碼而不阻塞UI,可以用來做需要大量計算的事情,充分利用CPU多核。

大家可以看看這篇文章介紹https://www.html5rocks.com/en/tutorials/workers/basics/, 或者對應的中文版

The Web Workers specification defines an API for spawning background scripts in your web application. Web Workers allow you to do things like fire up long-running scripts to handle computationally intensive tasks, but without blocking the UI or other scripts to handle user interactions.

可以開啟這個連結自己體驗一下WebWorkers的加速效果。

現在瀏覽器基本都支援WebWorkers了caniuse-webworkers

Parallel.js

直接使用WebWorkers介面還是太繁瑣,好在有人已經對此作了封裝:Parallel.js

注意Parallel.js可以通過node安裝:

不過這個是在node.js下用的,用的node的cluster模組。如果要在瀏覽器裡使用的話, 需要直接應用js:

然後可以得到一個全域性變數,ParallelParallel提供了mapreduce兩個函數語言程式設計的介面,可以非常方便的進行併發操作。

我們先來定義一下我們的問題,由於業務比較複雜,我這裡把問題簡化成求1-1,0000,0000的和,然後在依次減去1-1,0000,0000,答案顯而易見: 0! 這樣做是因為數字太大的話會有資料精度的問題,兩種方法的結果會有一些差異,會讓人覺得並行的方法不可靠。此問題在我的mac pro chrome61下直接簡單地跑js執行的話大概是1.5s(我們實際業務問題需要15s,這裡為了避免使用者測試的時候把瀏覽器搞死,我們簡化了問題)。

程式碼比較簡單,我這裡說幾個剛用的時候遇到的坑。

  • require所有需要的函式

比如在上訴程式碼中用到了sum,你需要提前require(sum),如果sum中由用到了另一個函式f,你還需要require(f),同樣如果f中用到了g,則還需要require(g),直到你require了所有用到的定義的函式。。。。

  • 沒法require變數

我們上訴程式碼我本來定義了N1,但是沒法用

  • ES6編譯成ES5之後的問題以及Chrome沒報錯

實際專案中一開始我們用到了ES6的特性:陣列解構。本來這是很簡單的特性,現在大部分瀏覽器都已經支援了,不過我當時配置的babel會編譯成ES5,所以會生成程式碼_slicedToArray,大家可以線上上Babel測試,然後Chrome下面始終不work,也沒有任何報錯資訊,查了很久,後來在Firefox下開啟,有報錯資訊:

看來Chrome也不是萬能的啊。。。

大家可以在此Demo頁面測試, 提速大概在4倍左右,當然還是得看自己電腦CPU的核數。 另外我後來在同樣的電腦上Firefox55.0.3(64位)測試,上訴程式碼居然只要190ms!!!在Safari9.1.1下也是190ms左右。。。

Refers

相關文章