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

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

Alex Danilo

WebAssembly (Wasm) 可讓您編譯以 C++ 和其他語言編寫的程式碼,以便在網路上執行。原生應用程式的一項實用功能,就是能夠使用執行緒,也就是用於並行運算的原始碼。大多數 C 和 C++ 開發人員都熟悉 pthreads,這是應用程式中用於執行緒管理的標準化 API。

WebAssembly 社群群組已致力於將執行緒帶入網路,以啟用真正的多執行緒應用程式。在這個努力的過程中,V8 已實作 WebAssembly 引擎中執行緒的必要支援功能,可透過Origin Trial 取得。開發人員可透過 Origin Trials 在新的網頁功能完全標準化前,先行試驗。這讓我們能夠向 inrepid 開發人員收集實際意見回饋,這對驗證及改善新功能至關重要。

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

執行緒?那麼 Workers 呢?

自 2012 年起,瀏覽器在 Chrome 4 版中透過網路工作處理程序支援平行處理;實際上,聽到「在主執行緒上」等字詞是正常現象。然而,網路工作站之間的通訊是不會共用可變動的資料,而是仰賴訊息傳遞來進行通訊。事實上,Chrome 會為每個隔離程序分配新的 V8 引擎。隔離不會共用已編譯的程式碼或 JavaScript 物件,因此無法共用 pthread 等可變動資料。

另一方面,WebAssembly 執行緒是可共用相同 Wasm 記憶體的執行緒。共用記憶體的基礎儲存空間是透過 SharedArrayBuffer 完成,這是 JavaScript 基元,允許在工作站之間並行共用單一 ArrayBuffer 的內容。每個 WebAssembly 執行緒都會在 Web Worker 中執行,但共用 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」則會指示編譯器產生兩個執行緒的集區。

執行程式時,程式會在幕後載入 WebAssembly 模組,為執行緒集區中的每個執行緒建立 Web Worker,並與各個 worker 共用該模組,在本例中為 2,這些會在每次呼叫 pthread_create() 時使用。每個 worker 都會使用相同的記憶體將 Wasm 模組例項化,以便進行合作。V8 7.0 中的最新變更會共用在工作站之間傳遞的 Wasm 模組編譯原生程式碼,因此即使是大型應用程式,也能擴充至多個工作站。請注意,請務必確保執行緒集區大小等於應用程式所需的執行緒數上限,否則執行緒建立作業可能會失敗。同時,如果執行緒集區大小過大,您將建立不必要的 Web Workers,這些工作站只會閒置,不做任何事情,只會使用記憶體。

如何試用

如要快速測試 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 模組載入及執行。開啟開發人員工具會顯示執行作業的輸出內容,主控台中應該會顯示如下的輸出影像:

斐波那契程式的控制台輸出內容

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

在實地使用「Origin Trial」進行測試

在瀏覽器中開啟實驗性標記,即可嘗試使用執行緒,這對於開發目的來說是可行的做法,但如果您想在實際環境中測試應用程式,可以使用所謂的來源測試

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

我們已使用來源試用權杖代管上述簡單範例,因此您不必建構任何內容,即可親自試用

如果您想瞭解 4 個並行執行的執行緒可為 ASCII 藝術做什麼,請務必觀看這個示範

提供意見

WebAssembly 執行緒是用於將應用程式移植至網際網路的極為實用的新原始元素。現在您可以執行需要 WebAssembly 環境中支援 pthreads 的 C 和 C++ 應用程式和程式庫。

我們正在徵求試用這項功能的開發人員的意見回饋,因為這有助於將功能標準化,並驗證其實用性。如要提供意見回饋,最佳做法是回報問題和/或參與 WebAssembly 社群群組標準化程序。