體驗WebAssembly

碎碎醬發表於2018-10-24

原文地址: github.com/yinxin630/b…
技術交流: fiora.suisuijiang.com/

WebAssembly是什麼

WebAssembly是一種執行在現代網路瀏覽器中的新型程式碼並且提供新的效能特性和效果。它設計的目的不是為了手寫程式碼而是為諸如C、C++和Rust等低階源語言提供一個高效的編譯目標。

對於網路平臺而言,這具有巨大的意義——這為客戶端app提供了一種在網路平臺以接近本地速度的方式執行多種語言編寫的程式碼的方式;在這之前,客戶端app是不可能做到的。

而且,你可以在不知道如何編寫WebAssembly程式碼的情況下就可以使用它。WebAssembly的模組可以被匯入的到一個網路app(或Node.js)中,並且暴露出供JavaScript使用的WebAssembly函式。JavaScript框架不但可以使用WebAssembly獲得巨大效能優勢和新特性,而且還能使得各種功能保持對網路開發者的易用性。''

簡言之, WebAssembly使得C/C++的程式碼可以在瀏覽器中執行

有什麼好處呢? 一是 C/C++ 程式碼的執行效率優於 JavaScript, 可以提升 Web 應用的效能表現. 二是有機會將現有的 C/C++ 應用遷移到 Web 平臺, 享受 Web 易傳播的紅利

環境安裝 (MacOS)

要編譯 C/C++ 到 wasm 需要安裝 Emscripten 工具, 為了安裝 Emscripten 你需要具備如下環境:

  • Git
  • Cmake
  • Xcode
  • Python 2.7.x

上述環境準備完畢後, 我們要編譯 Emscripten, 按序執行如下命令:

git clone https://github.com/juj/emsdk.git
cd emsdk
./emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit
./emsdk activate --global --build=Release sdk-incoming-64bit binaryen-master-64bit
複製程式碼

編譯過程中會安裝 Node.js, 即便你已經具備 Node.js 環境了, 如果在下載 Node.js 時報了網路錯誤, 請科學上網後再試

其他系統安裝請參考: developer.mozilla.org/zh-CN/docs/…

生成 WebAssembly

建立 hello.c 檔案, 複製如下程式碼

#include <stdio.h>

int main(int argc, char ** argv) {
    printf("Hello World\n");
}
複製程式碼

然後將 c 原始碼檔案編譯為 js 檔案, Emscripten 並不會自動新增到 PATH 中, 你需要在安裝目錄中執行如下命令

emcc hello.c -s WASM=1 -o hello.js
複製程式碼

建立 hello.html 檔案, 載入該 js 檔案

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Web Assembly</title>
</head>
<body>
    <script src="./hello.js"></script>
</body>
</html>
複製程式碼

你需要通過 HTTP 協議來訪問這個頁面 可以用 nginx 或者代理軟體, 還可以安裝 http-server 這個 npm 包, 執行 npm install http-server -g, 執行服務 http-server

開啟頁面, 檢視 console, 會輸出 Hello World

將 Emscripten 新增到環境變數

emcc 位於 [安裝目錄]/emsdk/emscripten/incoming/

在 JavaScript 中呼叫 C 定義的函式

建立 callc.c 檔案, 複製如下程式碼

#include <stdio.h>
#include <emscripten/emscripten.h>

#ifdef __cplusplus
extern "C" {
#endif

int EMSCRIPTEN_KEEPALIVE cPow(int num) {
    printf("我的C函式已被呼叫\n");
    printf("引數 num = %d\n", num);
    return num * num;
}

#ifdef __cplusplus
}
#endif
複製程式碼

編譯到 js

emcc callc.c -s WASM=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall']" -o callc.js
複製程式碼

建立 callc.html 檔案, 載入 js 檔案並呼叫方法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Web Assembly</title>
</head>
<body>
    <script src="./callc.js"></script>
    <script>
        window.onload = () => {
            var result = Module.ccall(
                'cPow', // C函式名
                'number', // 返回值型別
                ['number'], // 各引數型別
                [10], // 各引數值
            );
            console.log(`返回值 result = ${result}`);
        }
    </script>
</body>
</html>
複製程式碼

開啟頁面, 檢視 console

減小生成的 js 和 wasm 檔案體積

前面的第一個例子, 生成的檔案體積如下圖

image.png

新增優化引數並重新執行命令生成, emcc hello.c -s WASM=1 -O3 -o hello.js, 這次生成的檔案體積如下圖

image.png

另外生成的檔案體積與 C 程式碼中依賴的標準庫數量是成正比的, 用到 strlen, flockfile, funlockfile, memcpy, fwrite, fputs 等方法越多, 生成的提交越大

參考連結

developer.mozilla.org/zh-CN/docs/… kripken.github.io/emscripten-…

相關文章