現在可以在 Chrome 70 版中試用 WebAssembly Thread

在 Chrome 70 版中,WebAssembly 執行緒支援功能已在來源試用階段推出。

Alex Danilo

WebAssembly (Wasm) 可針對以 C++ 和其他語言編寫的程式碼編譯,並在網路上執行。原生應用程式的其中一項實用功能是可使用執行緒,這是平行運算的基礎。大部分的 C 和 C++ 開發人員都會熟悉 pthreads,這是在應用程式中用於管理執行緒的標準化 API。

WebAssembly 社群群組一直致力於將執行緒遷移至網路,以實現真正的多執行緒應用程式。為此,V8 已在 WebAssembly 引擎中針對執行緒導入必要支援,我們會透過來源試用提供這項支援。來源試用可讓開發人員在新的網頁功能完全標準化前先行實驗。這可讓我們收集無害的開發人員實際意見回饋,這對於驗證及改善新功能來說至關重要。

Chrome 70 版支援 WebAssembly 的執行緒,我們也鼓勵感興趣的開發人員開始使用這些執行緒並提供意見回饋。

執行緒?那 worker 呢?

自 2012 年起,瀏覽器在 Chrome 4 中透過 Web Worker 支援平行處理功能;事實上,瀏覽器之間不會出現「在主執行緒上」等字詞。然而,網路工作站不會在兩者之間共用可變動資料,而是依賴訊息傳遞來通訊。事實上,Chrome 會為每個 API 分配一個新的 V8 引擎 (稱為「隔離模式」)。隔離時不會共用編譯的程式碼和 JavaScript 物件,因此無法分享 pthread 等可變動資料。

另一方面,WebAssembly 執行緒是可以共用相同的 Wasm 記憶體的執行緒。共用記憶體的基礎儲存空間是透過 SharedArrayBuffer 取得,這是一種 JavaScript 原始版本,可讓工作站在工作站之間並行共用單一 ArrayBuffer 的內容。每個 WebAssembly 執行緒都會在網路工作站中執行,但共用的 Wasm 記憶體允許其在原生平台上運作。這表示使用 Wasm 執行緒的應用程式會像使用任何傳統執行緒應用程式一樣,負責管理共用記憶體的存取權。有許多以 C 或 C++ 編寫的現有程式碼程式庫使用 pthreads,這些程式庫可編譯為 Wasm,並以真實執行緒模式執行,進而讓更多核心可同時處理相同資料。

簡易範例

以下是使用執行緒的簡易「C」程式範例。

#include <pthread.h>
#include <stdio.h>

// Calculate Fibonacci numbers shared function
int fibonacci(int iterations) {
    int     val = 1;
    int     last = 0;

    if (iterations == 0) {
        return 0;
    }
    for (int i = 1; i < iterations; i++) {
        int     seq;

        seq = val + last;
        last = val;
        val = seq;
    }
    return val;
}
// Start function for the background thread
void *bg_func(void *arg) {
    int     *iter = (void *)arg;

    *iter = fibonacci(*iter);
    return arg;
}
// Foreground thread and main entry point
int main(int argc, char *argv[]) {
    int         fg_val = 54;
    int         bg_val = 42;
    pthread_t   bg_thread;

    // Create the background thread
    if (pthread_create(&bg_thread, NULL, bg_func, &bg_val)) {
        perror("Thread create failed");
        return 1;
    }
    // Calculate on the foreground thread
    fg_val = fibonacci(fg_val);
    // Wait for background thread to finish
    if (pthread_join(bg_thread, NULL)) {
        perror("Thread join failed");
        return 2;
    }
    // Show the result from background and foreground threads
    printf("Fib(42) is %d, Fib(6 * 9) is %d\n", bg_val, fg_val);

    return 0;
}

這個程式碼是以 main() 函式開頭,後者會宣告 2 個變數 fg_valbg_val。另外還有一個名為 fibonacci() 的函式,在這個範例中,兩個執行緒都會呼叫這個函式。main() 函式會使用 pthread_create() 建立背景執行緒,此執行緒的工作是計算與 bg_val 變數值對應的纖維數序列值。同時,在前景執行緒執行的 main() 函式會計算 fg_val 變數。背景執行緒執行完畢後,結果就會輸出列印出來。

執行緒支援編譯

首先,您應該安裝 emscripten SDK (最好是 1.38.11 以上版本)。如要建構啟用執行緒並在瀏覽器中執行的範例程式碼,我們需要將一些額外標記傳遞至 emscripten emcc 編譯器。我們的指令列如下所示:

emcc -O2 -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=2 -o test.js test.c

指令列引數「-s USE_PTHREADS=1」會開啟已編譯 WebAssembly 模組的執行緒支援,而引數「-s PTHREAD_POOL_SIZE=2」會告知編譯器產生兩個 (2) 個執行緒集區。

程式執行時,會在背景載入 WebAssembly 模組,為執行緒集區中的每個執行緒建立網路工作站,與各個工作站共用該模組 (在本例中為 2),而會在呼叫 pthread_create() 時使用這些模組。每個工作站都會使用相同的記憶體執行個體化 Wasm 模組,使其可以合作。V8 最新的 7.0 版變更分享了經過編譯的 Wasm 模組原生程式碼,這類程式碼會在工作站之間傳遞,讓非常大型的應用程式能夠擴充到許多工作站。請注意,請確保執行緒集區大小等於應用程式所需的執行緒數量上限,否則可能無法建立執行緒。與此同時,如果執行緒集區的大小太大,就會建立不必要的 Web Worker,而網路工作站只會專心處理記憶體。

試用方法

如要測試 WebAssembly 模組,最快的方式是在 Chrome 70 以上版本中啟用實驗性 WebAssembly 執行緒支援。在瀏覽器中前往網址 about://flags,如下所示:

Chrome 旗標頁面

接著,請找出如下所示的實驗性 WebAssembly 執行緒設定:

WebAssembly 執行緒設定

將設定變更為「已啟用」 (如下所示),然後重新啟動瀏覽器。

已啟用 WebAssembly 執行緒設定

瀏覽器重新啟動後,我們可以嘗試透過最小的 HTML 頁面載入執行緒的 WebAssembly 模組,其僅包含以下內容:

<!DOCTYPE html>
<html>
  <title>Threads test</title>
  <body>
    <script src="test.js"></script>
  </body>
</html>

如要試用這個頁面,您必須執行某種形式的網路伺服器,並透過瀏覽器載入該伺服器。這樣就會載入並執行 WebAssembly 模組。開啟開發人員工具後,系統會顯示執行作業的輸出內容,而主控台中會顯示以下的輸出圖片:

Fibonacci 程式的主控台輸出內容

我們的含有執行緒的 WebAssembly 程式已成功執行!建議您依照上述步驟,試用自己的執行緒應用程式。

透過來源試用在實際環境中進行測試

基於開發作業需求,您可以在瀏覽器中啟用實驗性旗標來試用執行緒,但如果您想在實際環境中測試應用程式,則適用所謂的「來源試用」

來源試用可讓您取得與您網域相關聯的測試權杖,藉此與使用者試用實驗功能。接著,您可以部署應用程式,並預期應用程式在支援您正在測試的功能的瀏覽器上運作 (在本例中為 Chrome 70 以上版本)。如要取得自己的權杖來執行來源試用,請使用這裡的申請表單。

我們在上方使用來源試用權杖託管了簡易範例,方便您自行試用,無須建構任何程式。

如果您想瞭解平行執行的 4 個執行緒可以為 ASCII 藝術,請一併參閱這個示範內容

提供意見

WebAssembly 執行緒是非常實用的新基本功能,可將應用程式移植到網路。您現在可以在 WebAssembly 環境中執行需要 pthreads 支援的 C 和 C++ 應用程式和程式庫。

我們希望開發人員在試用這項功能時,提供意見回饋,不僅能協助完成標準化程序,也有助於驗證這項功能的實用性。如要提供意見回饋,最佳做法是回報問題並/或參與 WebAssembly 社群群組中的標準化程序。