1 什么是WASM
WASM是WebAssembly的縮寫,WebAssembly是一種用于基于堆棧虛擬機的二進制指令格式。Wasm 被設計為編程語言的可移植編譯目標,支持在Web上為客戶端和服務器應用程序服務部署∩龋總結起來WASM是一種可以在現(xiàn)代Web瀏覽器種運行的新型代碼耐朴,是一種類似低級匯編的語言,擁有緊湊的二進制格式盹憎,能夠以接近本機的性能運行筛峭。為高級語言(C/C++、Go陪每、Rust影晓、Python等)提供編譯目標,通過這種方式Rust編寫的程序就可以在Web中運行檩禾。WASM和JS可以一起配合工作挂签。
2 WASM的特點
2.1 高效快速
WASM非常的輕量且加載速度極快。WASM的目標是以原生的速度運行盼产,從而充分利用各種平臺都擁有的通用硬件能力饵婆。使用最常見、最普通的硬件提升軟件運行的效率辆飘。
2.2 安全
WebAssembly 描述了一個內存安全的沙箱執(zhí)行環(huán)境啦辐,甚至可以在現(xiàn)有的 JavaScript 虛擬機中實現(xiàn)谓传。當嵌入到 Web 中時蜈项,WebAssembly 將強制執(zhí)行瀏覽器的同源和權限安全策略。
2.3 開放可調試
WebAssembly 旨在以文本格式漂亮地打印調試信息续挟,用于調試紧卒、測試、實驗诗祸、優(yōu)化跑芳、學習、教學和手工編寫程序(這個有點酷)直颅。在網絡上查看 Wasm 模塊的源時將使用文本格式(這簡直是調試的魔法糖)博个。
2.4 開放Web平臺的一部分
WebAssembly 旨在保持 Web 的無版本、功能測試和向后兼容的特性功偿。WebAssembly 模塊能夠在JavaScript上下文內外調用盆佣,可以訪問瀏覽器的函數(shù)。WebAssembly也支持在非瀏覽器環(huán)境運行械荷。
3 WSAI
WASM如此的優(yōu)秀共耍,偉大的程序員當然不想WASM只能在Web中得到應用,WASM應該在任何系統(tǒng)吨瞎、設備上得到應用痹兜,為此設計了WASM的模塊化系統(tǒng)接口WASI,通過標準的接口和主機環(huán)境進行交互颤诀。
4 運行時
WASM的執(zhí)行依賴運行時環(huán)境字旭,目前字節(jié)聯(lián)盟開發(fā)了單機的輕量化運行時wasmtime对湃。wasmtime非常的輕巧,Windows下大小只有2MB左右谐算。
wasmtime的主要特點包括:
輕量:WASM的單機運行時熟尉,可按需擴展。微信芯片和大型服務器都是無縫使用洲脂〗锒可內嵌到大多數(shù)的應用程序。因為輕量可以無處不在恐锦。
快:建立在優(yōu)化的 Cranelift 代碼生成器之上往果,可以在運行時快速生成高質量的機器代碼。
可配置:無論您需要提前預編譯您的 wasm 還是在運行時解釋它一铅,Wasmtime 都能滿足您執(zhí)行 wasm 的所有需求陕贮。
WASI支持:支持豐富的API集合,通過WASI標準和主機環(huán)境交互潘飘。
標準:Wasmtime 通過了官方的 WebAssembly 測試肮之,實現(xiàn)了 wasm 的官方 C API,也實現(xiàn)了未來對 WebAssembly 的提案卜录。 Wasmtime 開發(fā)人員也一直密切參與 WebAssembly 標準流程戈擒。
5 快速體驗
5.1 使用Rust編寫WASM
可以使用rust工具將rust源碼編譯為wasm,所以我們可以用Rust語言編寫程序艰毒,然后編譯成wasm格式筐高,然后使用wasmtime運行wasm或者在其他語言比如Go中運行wasm,這聽起來是不是很酷,下面以一個簡單的程序進行說明丑瞧。
第一步:將WebAssembly設置為cargo編譯的目標對象
rustup target add wasm32-wasi
第二步:創(chuàng)建一個簡單的Rust項目
cargo new hello-wasm
將main.rs函數(shù)修改為如下:
fn main() {
println!("Hello, WASM")
}
第三步:將Rust代碼編譯成WASM
cargo build --target wasm32-wasi
在hello-wasm/target/wasm32-wasi/debug目錄下可以找到編譯后的文件hello-wasm.wasm
5.2 使用wasmtime運行wasm
在hello-wasm.wasm所在的目錄打開命令行柑土,執(zhí)行下面的命令運行wasm:
wasmtime hello-wasm.wasm
屏幕上將會正確打印:Hello, WASM
檢查wasmtime是否正確安裝
下面我們按照WASM的規(guī)范編寫一個計算最大公約數(shù)gcd的函數(shù)绊汹,然后使用多種熟悉的編程語言去調用gcd函數(shù)稽屏。
gcd.wat的內容如下:
(module
(func $gcd (param i32 i32) (result i32)
(local i32)
block ;; label = @1
block ;; label = @2
local.get 0
br_if 0 (;@2;)
local.get 1
local.set 2
br 1 (;@1;)
end
loop ;; label = @2
local.get 1
local.get 0
local.tee 2
i32.rem_u
local.set 0
local.get 2
local.set 1
local.get 0
br_if 0 (;@2;)
end
end
local.get 2
)
(export "gcd" (func $gcd))
)
5.3 使用Rust運行gcd函數(shù)
第一步:創(chuàng)建gcd項目
cargo new gcd
第二步:添加依賴
[dependencies]
wasmtime = "0.31.0"
anyhow = "1.0.45"
第三步:編寫main.rs代碼運行gcd函數(shù)
use anyhow::Result;
use wasmtime::*;
fn main() -> Result<()> {
let mut store = Store::<()>::default();
let module = Module::from_file(store.engine(), "gcd.wat")?;
let instance = Instance::new(&mut store, &module, &[])?;
let gcd = instance.get_typed_func::<(i32, i32), i32, _>(&mut store, "gcd")?;
println!("gcd(6, 27) = {}", gcd.call(&mut store, (6, 27))?);
Ok(())
}
第四步:運行程序查看輸出結果
cargo run
程序將會輸出:
gcd(6, 27) = 3
5.4 使用Bash運行wasm
第一步:編寫gcd.sh
運行gcd函數(shù)
#!/bin/bash
function gcd() {
# Cast to number; default = 0
local x=$(($1))
local y=$(($2))
# Invoke GCD from module; suppress stderr
local result=$(wasmtime gcd.wat --invoke gcd $x $y 2>/dev/null)
echo "$result"
}
# main
for num in "27 6" "6 27" "42 12"; do
set -- $num
echo "gcd($1, $2) = $(gcd "$1" "$2")"
done
第二步:運行gcd.sh
sh gcd.sh
程序將會輸出:
gcd(27, 6) = 3
gcd(6, 27) = 3
gcd(42, 12) = 6
5.5 使用Python運行gcd
第一步:安裝wasmtime
pip install wasmtime
第二步:編寫gcd.py
代碼運行gcd函數(shù)
from wasmtime import Store, Module, Instance
store = Store()
module = Module.from_file(store.engine, 'gcd.wat')
instance = Instance(store, module, [])
gcd = instance.exports(store)["gcd"]
print("gcd(6, 27) = %d" % gcd(store, 6, 27))
第三步:運行gcd.py
python gcd.py
程序將會輸出:
gcd(6, 27) = 3