#include // 遞歸方式計算斐波那契數列的第n個數
int fibonacci(int n) {
if (n <= 1) return n; return fibonacci(n - 1) + fibonacci(n - 2);
}
int main() {
int n; std::cout << "請輸入斐波那契數列的項數:"; std::cin >> n; std::cout << fibonacci(n); return 0;
}
g++ fib.cpp -o fib && ./fib
Emscripten 是一個完整的 WebAssembly 編譯器工具鏈,使用 LLVM,特別關注速度、大小和 Web 平臺。
這里又引入了一個新概念:LLVM。LLVM(Low-Level Virtual Machine) 是一個開源的編譯器基礎設施項目,它提供了一組模塊化的編譯器和工具,用于構建、優化和執行程序。LLVM 最初是為編譯器開發而設計的,但它已經演變成一個通用的編譯器基礎設施,可以用于多種編程語言和領域。
LLVM 的主要組件包括:
- 前端:LLVM 支持多種編程語言的前端,包括 C/C++、Rust、Swift、Python 等。這些前端將源代碼轉換成一種稱為
LLVM IR(Intermediate Representation)的中間代碼。 - 中間表示(LLVM IR):LLVM IR 是一種類似匯編語言的中間代碼,它是 LLVM 的核心。所有支持的編程語言都被翻譯成 LLVM IR,這樣可以在后續的優化階段進行通用的編譯器優化。
- 優化器:LLVM 包含強大的優化器,它可以在不改變程序語義的情況下提高代碼的性能。這些優化包括死代碼刪除、內聯函數、循環優化等。類似 JS 構建領域的代碼壓縮器。
- 后端:LLVM 還包括用于不同目標架構的后端代碼生成器。這意味著你可以使用 LLVM 來生成針對不同硬件架構的機器碼,從而實現跨平臺的編譯。
- 工具:LLVM 提供了許多輔助工具,用于調試、分析和測試代碼。
對于軟件工程師來說,LLVM 在編譯器開發、代碼優化和跨平臺編譯方面具有重要意義。它還被廣泛用于編程語言的實現和各種編譯器項目中。
Emscripten 安裝
官網有多種安裝方式,這里我們使用推薦的 emsdk。
我們將使用了三方模塊的 c++ 代碼,編譯為了 wasm,但是有個關鍵問題沒解決:如何將 JS 與 wasm 當中的數據互傳?
wasm 可以理解成獨立工作的 Worker 線程,但是 JS 的線程模型和 Java 這種多線程模型的語言不同,JS 內創建的一些對象、字符串等都存在于 V8 等虛擬機的堆內存里,外部線程無法直接操作。而 Java 為代表的多線程語言,線程共享同一塊內存區域,可以任意讀寫(但是存在并發問題)。
斐波那契函數的示例,不存在此問題,因為 wasm 虛擬機本身就支持 int 32/int64/float 等整數、浮點數數據類型的傳遞。
可以看到,上述流程當中,最關鍵的就 2 個核心要素:
- JS 與 wasm 互傳的數據只能是整數、浮點數
- wasm 有暴露共享的 ArrayBuffer 供 JS 操作,以達到互傳數據的目的
對于上線的項目:
1、使用wasm由于體積大小的問題,不要放在main.js里面去打包,會阻塞白屏時間
2、采用異步加載的方式
3、對于編解碼或者耗資源的情況,建議放到web worker中進行實例化,在處理業務邏輯