Chrome 70 已在原始試用版中提供 WebAssembly 執行緒支援功能。
WebAssembly (Wasm) 可讓您編譯以 C++ 和其他語言編寫的程式碼,以便在網路上執行。原生應用程式的一項實用功能,就是能夠使用執行緒,這是用於並行運算的原始元素。大多數 C 和 C++ 開發人員都熟悉 pthreads,這是應用程式中用於執行緒管理的標準化 API。
WebAssembly 社群群組一直致力於將執行緒帶入網際網路,以便啟用真正的多執行緒應用程式。在這個努力的過程中,V8 已實作 WebAssembly 引擎中執行緒的必要支援功能,可透過Origin Trial 取得。開發人員可透過 Origin Trials 在新的網頁功能全面標準化前,先進行實驗。這樣一來,我們就能向大膽的開發人員收集實際意見回饋,這對於驗證及改善新功能至關重要。
Chrome 70 版本支援 WebAssembly 的執行緒,我們鼓勵有興趣的開發人員開始使用這些執行緒,並提供意見回饋。
執行緒?那麼 Workers 呢?
自 2012 年 Chrome 4 起,瀏覽器就支援透過 Web Workers 執行並行作業。事實上,您經常會聽到「在主執行緒上」等術語。不過,Web Workers 不會在彼此之間共用可變動資料,而是仰賴訊息傳遞進行通訊。事實上,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_val
和 bg_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
,如下所示:
接著,找出實驗性的 WebAssembly 執行緒設定,如下所示:
將設定變更為「啟用」,如以下所示,然後重新啟動瀏覽器。
瀏覽器重新啟動後,我們可以嘗試使用最少的 HTML 頁面載入執行緒化的 WebAssembly 模組,其中只包含以下內容:
<!DOCTYPE html>
<html>
<title>Threads test</title>
<body>
<script src="test.js"></script>
</body>
</html>
如要試用這個網頁,您必須執行某種形式的網路伺服器,並從瀏覽器載入該伺服器。這會導致 WebAssembly 模組載入及執行。開啟 DevTools 後,您會看到執行作業的輸出內容,控制台應會顯示類似下圖的輸出內容:
我們的 WebAssembly 程式已成功執行執行緒!建議您按照上述步驟,試用自己的執行緒應用程式。
在實際環境中使用來源試用功能進行測試
在瀏覽器中開啟實驗性標記,即可嘗試使用執行緒,這對於開發目的來說是可行的做法,但如果您想在實際環境中測試應用程式,可以使用所謂的來源測試。
透過原點測試,您可以取得與網域相關聯的測試權杖,讓使用者試用實驗功能。接著,您可以部署應用程式,並預期應用程式可在支援您測試功能的瀏覽器中運作 (在本例中為 Chrome 70 以上版本)。如要取得自己的權杖來執行原始試用版,請使用這份表單申請。
我們已使用來源試用權杖代管上述簡單範例,因此您不必建構任何內容,即可親自試用。
如果您想瞭解 4 個並行執行的執行緒可為 ASCII 藝術做什麼,請務必觀看這個示範!
提供意見
WebAssembly 執行緒是用於將應用程式移植至網際網路的非常實用的新原始元素。您現在可以在 WebAssembly 環境中,執行需要 pthreads 支援的 C 和 C++ 應用程式和程式庫。
我們希望開發人員試用這項功能後提供意見回饋,以便我們進行標準化程序,並驗證這項功能的實用性。提供意見回饋的最佳方式是回報問題,以及/或是參與 WebAssembly 社群群組的標準化程序。