给Web前端工程师看的用Rust开发wasm组件实战
浠涔堟槸wasm缁勪欢锛
wasm 鍏ㄧО WebAssembly锛屾槸閫氳繃铏氭嫙鏈虹殑鏂瑰紡锛屽彲浠ュ湪鏈嶅姟绔佸鎴风濡傛祻瑙堝櫒绛夌幆澧冩墽琛岀殑浜岃繘鍒剁▼搴忋傚畠鏈夐熷害蹇佹晥鐜囬珮銆佸彲绉绘鐨勭壒鐐广
瀵规垜浠 Web 鍓嶇宸ョ▼鏈澶х殑濂藉灏辨槸鍙互鍦ㄦ祻瑙堝櫒绔娇鐢ㄤ簩杩涘埗绋嬪簭澶勭悊涓浜涜绠楅噺澶х殑澶勭悊锛屼娇鐢ㄤ粬姣 javascript 蹇殑鐗圭偣浼樺寲鎬ц兘銆
鐩墠娴忚鍣ㄥwasm鐨勫吋瀹规у涓嬶細
鍦ㄧЩ鍔ㄧ闄や簡 android 4.4 鍜 ios 10 涓嬩笉鏀寔澶栵紝鍏朵粬鐗堟湰閮借兘鎻愪緵鏀寔銆傝繕闇瑕佹敞鎰忕殑鏄 wasm 鏈夊彲鑳藉崰鐢ㄥぇ閲忓唴瀛橈紝浣跨敤绗笁鏂瑰寘鍚 wasm 璋冪敤鐨勭粍浠堕渶瑕佹敞鎰忓唴瀛樺崰鐢ㄩ槻姝㈤棯閫銆
涓轰粈涔堢敤Rust锛
wasm妯″潡 鍙互鐢ㄥ绉嶈瑷鏉ョ紪璇戯紝鍖呮嫭 C/C++/C#銆丷ust銆丣AVA銆丟o銆傚湪杩欓噷浣跨敤 Rust 鏄洜涓轰粬鏈変弗鏍肩殑鍐呭瓨绠$悊鏈哄埗锛屼粠璇硶涓婂敖閲忛伩鍏嶅唴瀛樻孩鍑猴紝璁╁伐绋嬪笀鍐欏嚭鏇村畨鍏ㄧ殑绋嬪簭銆
鑰屼笖杩樻湁閰嶅鐨勫伐鍏 wasm-pack锛岃浣跨敤 Rust 缂栧啓鐨勪唬鐮侊紝缂栬瘧鍖呰鎴 npm 鍖咃紝璁╀娇鐢ㄨ繖娈电▼搴忕殑鍏朵粬浠g爜鍙互鍍忎娇鐢ㄥ叾浠栧叕鍏卞簱涓鏍疯皟鐢紝涓嶉渶瑕侀澶栧涔犳垚鏈
宸ュ叿瀹夎
瀹夎 rustup锛屽畠鏄 Rust 瀹夎鍣ㄥ拰鐗堟湰绠$悊宸ュ叿銆傚浜 web 鍓嶇鏉ヨ鐩稿綋浜 nvm 杩欐牱鐨勫伐鍏枫傛寜鐓 Rust 瀹樼綉鐨勬柟娉曞畨瑁咃細https://www.rust-lang.org/zh-CN/tools/install鍚屾椂涔熶細瀹夎 cargo锛屽畠鏄 Rust 鐨勬瀯寤哄伐鍏峰拰鍖呯鐞嗗櫒銆傚浜 web 鍓嶇鏉ヨ鐩稿綋浜 npm 杩欐牱鐨勫伐鍏枫
瀹夎 wasm-pack锛屼粬鏄笂鏂囨彁鍒扮殑鎶 Rust 绋嬪簭缂栬瘧鍖呰鎴 wasm 缁勪欢鐨勫伐鍏枫傚悓鏍锋寜鐓 wasm-pack 瀹樼綉鐨勬柟娉曞畨瑁咃細https://rustwasm.github.io/wasm-pack/installer/
浣跨敤 wasm 妯℃澘浣跨敤 wasm-pack 鎻愪緵鐨勬ā鏉垮彲浠ュ揩閫熺敓鎴 Rust 鐨 wasm 椤圭洰銆
cargo generate --git https://github.com/rustwasm/wasm-pack-template
杈撳叆甯屾湜鐨勯」鐩洰褰曞悕绉帮紝灏嗘柊寤虹洰褰曞苟鍦ㄥ叾涓敓鎴愰」鐩
鍦ㄧ洰褰曚笅鎴戜滑鍙互鐪嬪埌鍑犱釜鏂囦欢锛屽叾涓竴涓槸 Cargo.toml 锛岃繖涓槸 Rust 椤圭洰鐨勬弿杩版枃浠讹紝瀵逛簬 web 鍓嶇鏉ヨ鐩稿綋浜 package.json 鏂囦欢銆
椤圭洰鐩綍涓嬭繕鏈変竴涓 src 鐩綍锛岄噷闈㈡湁 lib.rs 鍜 utils.rs 涓や釜鏂囦欢锛屽叾涓 lib.rs 杩欎釜鏂囦欢灏辨槸鎴戜滑涓昏鐨勯昏緫鍏ュ彛锛屼粬寮曠敤浜 wasm-bindgen 搴撴潵杈撳嚭鏆撮湶缁欏閮ㄨ皟鐢ㄧ殑鎺ュ彛锛屽湪鍑芥暟涔嬪墠鍔犱笂
#[wasm_bindgen]
鍙互璁╁閮ㄨ皟鐢ㄨ繖涓柟娉曘缂栬瘧椤圭洰
鏈潵 Rust 鐨勯」鐩紪璇戠敤鐨勬槸 cargo build 鐨勫懡浠わ紝浣嗘槸鎴戜滑杩欓噷鏄笇鏈涚紪璇 wasm 缁勪欢锛屾墍浠ョ敤鐨勬槸 wasm-pack build 鍛戒护銆
鎵ц鍚庝細鍦ㄩ」鐩洰褰曚笅鐨 pkg 鐩綍涓嬬敓鎴愮紪璇戝悗鐨勪骇鍝侊紝鏄竴涓 npm 鍖呯殑缁撴瀯銆傞渶瑕佽皟鐢ㄨ繖涓粍浠剁殑閫昏緫鍙渶瑕佸儚鍏朵粬鍏叡鍖呬竴鏍 import 灏卞彲浠ヤ娇鐢ㄤ簡銆
瀹炴垬
浠ヤ笂鐨勫氨鏄 wasm-pack 瀹樻柟鐨勬暀绋嬶紝杩樻湁鍏朵粬缁勪欢娴嬭瘯銆佸彂甯冪瓑鐨勬祦绋嬪厛涓嶅湪杩欓噷浠嬬粛浜嗐備互涓嬬敤涓涓疄闄呭紑鍙戜腑鐨勬ā鍧楁潵璇翠竴涓嬪紑鍙 wasm 缁勪欢杩囩▼涓亣鍒扮殑闂鍜岃В鍐虫柟娉曘
鑳屾櫙鈥
闇瑕佷娇鐢ㄧ殑 wasm 缁勪欢鏄竴涓紭鍖3D妯″瀷鐨勬柟娉曪紝浼犲叆涓涓ā鍨嬬殑椤剁偣淇℃伅鍜岃窛绂婚槇鍊硷紝姣旇緝姣忎釜椤剁偣浣嶇疆涔嬮棿鐨勮窛绂伙紝濡傛灉娌¤揪鍒伴槇鍊艰窛绂诲氨鍚堝苟杩欎袱涓《鐐癸紝浠ヨ揪鍒板噺灏戦《鐐圭殑浼樺寲鐩殑銆
鍘熼昏緫鏄娇鐢 javascript 缂栧啓鐨勶紝鍦ㄦā鍨嬮《鐐规暟閲忔瘮杈冨鐨勬椂鍊欐墽琛岀殑鏃堕棿姣旇緝闀裤傝繖绉嶅ぇ閲忚绠楃殑鎯呭喌灏卞緢閫傚悎浣跨敤 wasm 鏉ュ鐞嗐
鏁版嵁浼犻掆
椤剁偣淇℃伅鏄瓨鍌ㄥ湪涓涓 Float32Array 鐨勬暟缁勪腑鐨勶紝鑰 wasm 璁捐涓婇櫎浜 int 鍜 float 绫诲瀷锛堝搴 javascript 灏辨槸 number 绫诲瀷锛夊彲浠ョ洿鎺ヤ紶閫掑锛屽叾浠栫殑绫诲瀷閮介氳繃鍦板潃鏉ヤ紶閫掋傝繖瀵规垜浠殑绋嬪簭鏉ヨ鏄ソ娑堟伅锛屽洜涓洪《鐐逛俊鎭殑鏁版嵁闈炲父澶氾紝濡傛灉浠ュ间紶閫掞紝灏遍渶瑕佸仛鏁版嵁澶嶅埗锛岃繖涓繃绋嬫秷鑰楃殑鏃堕棿鍙兘姣旀垜浠崲鎴 wasm 澶勭悊鍑忓皯鐨勬椂闂磋繕瑕佸銆傚緱鐩婅繖涓壒鐐癸紝鎴戜滑鐨勫叆鍙傚彲浠ョ洿鎺ヤ紶鍏ャ
/*--- rust ----*/
// rust 鑾峰彇 javasctipt 鏁版嵁
pub fn add_attribute(&mut self, attribute: &Float32Array, item_size: u32) {
self.attributes.push(BufferAttribute {
array: attribute.to_vec(),
item_size,
});
}
/*--- javascript ----*/
// javascript 浼犻掓暟鎹埌 rust
for (const name of attributeNames) {
const attr = attrArrays[name]
bg.add_attribute(attr.array, attr.itemSize)
}
鑰岃绠楀悗鐨勭粨鏋滐紝wasm 涔熸彁渚涗簡杩斿洖鏁扮粍鐨勬寚閽堝拰鏁扮粍闀垮害鐨勬柟娉曪紝javascript 鍙互璇诲彇 wasm 鐨勫唴瀛樼┖闂达紝鏍规嵁杩欎袱涓兼瀯閫犳柊鐨勯《鐐逛俊鎭疐loat32Array銆
/*--- rust ----*/
// 杩斿洖鎸囧畾鏁版嵁鐨勫唴瀛樻寚閽堜綅缃
pub fn get_attribute_ptr(&self, index: usize) -> *const f32 {
self.attributes[index].array.as_ptr()
}
// 杩斿洖鎸囧畾鏁版嵁鐨勯暱搴
pub fn get_attribute_length(&self, index: usize) -> usize {
self.attributes[index].array.len()
}
/*--- javascript ----*/
// javascript 鎴栧彇 rust 鍐呭瓨绌洪棿涓殑鎸囧畾閮ㄥ垎锛屾瀯寤篎loat32Array
const ptr = bg.get_attribute_ptr(i)
const length = bg.get_attribute_length(i)
const buffer = new attr.array.constructor(wasm.getMemory().buffer, ptr, length)
鏁版嵁绫诲瀷鈥
鍚堝苟椤剁偣璁$畻鐨勯昏緫涓紝鏈変竴娈垫槸杩欐牱鐨勶細姣忎釜椤剁偣鐨勪綅缃乁V绛変俊鎭紝缁忚繃缁欏畾鐨勭簿搴﹁绠楀悗锛岀敓鎴愪竴涓壒寰佸硷紝涔嬪悗姣旇緝姣忎釜椤剁偣鐨勭壒寰佸硷紝濡傛灉鏄浉鍚岀殑璇濆氨琛ㄧず杩欎袱涓《鐐瑰彲浠ュ悎骞躲
鍘 javascript 鐗堟湰鐨勪唬鐮佹槸閫愪釜淇℃伅鎸夐『搴忥紝鍔犱笂鍒嗛殧鍙凤紝鎷兼垚涓涓瓧绗︿覆銆
Rust 鐗堟湰鐨勪唬鐮佸鏋滀篃鎸夊悓鏍风殑鏂规硶澶勭悊锛屽洜涓洪《鐐圭殑淇℃伅閲忔槸涓嶅畾鐨勶紝鏈夊彲鑳藉彧鏈変綅缃俊鎭紝涔熸湁鍙兘鏈塙V銆佹硶绾裤侀鑹茬瓑淇℃伅锛屾墍浠ョ敓鎴愮殑鐗瑰緛鍊煎瓧绗︿覆闀垮害涔熶笉纭畾銆
Rust 瀵规柤鍙彉闀垮害鐨勫瓧绗︿覆浣跨敤 String 绫诲瀷锛屾瘡娆″瀛楃涓蹭娇鐢
push_str
鏂规硶澧炲姞鍐呭銆傚緱鍒扮殑缁撴灉 wasm 鐗堟湰鐨勬墽琛岄熷害璺 javascript 鐗堟湰鐩稿樊涓嶅ぇ锛岀敋鑷冲湪鏌愪簺鎯呭喌涓嬭楁椂杩樻洿澶氾紝缁忚繃閫愪釜杩囩▼浣滄帓鏌ワ紝鍙戠幇鏄湪鐢熸垚鐗瑰緛鍊煎拰鍦ㄨ〃涓煡璇㈢壒寰佸艰繖涓繃绋嬩腑鑺辫垂鐨勬椂闂存瘮杈冨銆鏍规嵁绋嬪簭鐨勬剰鍥撅紝鐗瑰緛鍊煎苟涓嶄竴瀹氳鏄瓧绗︿覆锛屽彧闇瑕佸湪涓嶅悓杈撳叆鍊肩殑鏃跺欒兘澶熻緭鍑虹浉鍏崇殑鍊煎氨鍙互锛岃繖璺熺敓鎴 hash 鍊肩殑闇姹傛槸涓鏍风殑锛屼簬鏄冭檻灏嗙壒寰佸肩敓鎴愭浛鎹㈡垚 hash 鍊艰绠椼
鍥犱负鍦ㄥ瓨鍌ㄧ壒寰佸肩殑琛ㄤ娇鐢ㄤ簡
std::collections::hash_map
绫诲瀷锛屼簬鏄 hash 鍊间篃浣跨敤浜嗗叾涓嬬殑std::collections::hash_map::DefaultHasher
绫绘潵璁$畻use std::collections::hash_map::DefaultHasher;
...
let mut hasher = DefaultHasher::new();
for j in 0..self.attributes.len() {
...
let value = (attr.array[i * attr.item_size as usize + index as usize]
* self.shift_multiplier)
.trunc() as i32;
hasher.write_i32(value);
...
}
let hash = hasher.finish();
闇瑕佹敞鎰忕殑鏄鍐欏叆涓嶅悓绫诲瀷鐨勫唴瀹癸紝闇瑕佽皟鐢ㄤ笉鍚岀殑鏂规硶锛岄《鐐逛俊鎭腑鐨勫兼槸姝h礋鍊奸兘鐢紝缁忚繃绮惧害璁$畻鍚庡彇鏁村緱鍒扮殑鍊肩被鍨嬫槸
i32
锛屾墍浠ョ敤write_i32
鏉ュ啓鍏ュ唴瀹广鐢熸垚鐨 hash 鍊间负
u64
锛屼綔涓hash_map
鐨key
璁板綍瀵瑰簲椤剁偣鐨勫簭鍙枫鏇挎崲鐗瑰緛鍊肩殑绫诲瀷涔嬪悗锛寃asm 鐗堟湰鐨勮楁椂杈惧埌浜 javascript 鐗堟湰鐨 1/2锛屽熀鏈鍚 wasm 璁捐鐨勬ц兘鑼冨洿銆
閫傞厤鎵撳寘宸ュ叿鈥
wasm-pack 宸ュ叿鎵撳寘鍑烘潵鐨 npm 鍖咃紝鍙互鐩存帴鍦╳ebpack涓嬪姞杞藉苟璋冪敤杩愯銆
鎴戜滑鍘熸湰鐨勯」鐩娇鐢 vite 鏋勫缓锛寁ite 瀵筰mport wasm 缁勪欢绛栫暐鍜 webpack 鐨勪笉涓鏍凤紝vite 鍔犺浇浼氳繑鍥炰竴涓姞杞芥柟娉曪紝璋冪敤鍔犺浇鏂规硶浼氳繑鍥炰竴涓 Promise锛宺esolve 鍚庢墠浼氳繑鍥炶窡 webpack 鍔犺浇涓鏍风殑 wasm 缁勪欢銆
鎴戜滑瑕佸 wasm-pack 鐢熸垚鐨勪骇鐗╀綔涓浜涗慨鏀癸紝鍋囪鎴戜滑鐨 wasm 缁勪欢鍛藉悕涓 merge_vertice_wasm锛岀敓鎴愮殑涓 js 鏂囦欢搴旇浼氬懡鍚嶄负
merge_vertice_wasm.js
锛屽唴瀹瑰涓嬶細import * as wasm from './merge_vertice_wasm_bg.wasm'
import { __wbg_set_wasm } as wasm_bg from './merge_vertice_wasm_bg.js'
__wbg_set_wasm(wasm);
export * from './merge_vertice_wasm_bg.js'
涓哄吋瀹 vite 鐨勫姞杞界瓥鐣ワ紝淇敼鎴愪笅闈㈢殑鍐呭
import * as wasm from './merge_vertice_wasm_bg.wasm'
import * as wasm_bg from './merge_vertice_wasm_bg.js'
let memory
if (wasm.default) {
wasm.default({
'./merge_vertice_wasm_bg.js': wasm_bg,
}).then(_wasm => {
memory = _wasm.memory
wasm_bg.__wbg_set_wasm(_wasm)
})
} else {
memory = _wasm.memory
wasm_bg.__wbg_set_wasm(wasm)
}
export * from './merge_vertice_wasm_bg.js'
export function getMemory() {
return memory
}
灏卞彲浠ュ湪 webpack 鍜 vite 涓嬮兘鍙互椤哄埄鍔犺浇骞惰繍琛屼簡銆
鍏朵腑澧炲姞浜
getMemory
鐨勬柟娉曚緵澶栭儴鑾峰彇 wasm 缁勪欢鐨勫唴瀛樼┖闂淬wasm 璋冪敤 javascript 鏂规硶鈥
褰撴垜浠湪璋冭瘯鍜屾祴璇曟ц兘琛ㄧ幇鏃讹紝闇瑕佹墦鍗版棩蹇楋紝鐢变簬鎴戜滑鐨 wasm 璺戝湪娴忚鍣ㄧ幆澧冧腑锛屾垜浠渶瑕佽皟鐢 javascript 鐨勬柟娉曪紝姣斿
console.log
鍜console.time
銆wasm-bindgen 搴撴彁渚涗簡 web-sys 鐨勭粍浠讹紝璁 Rust 鍙互璋冪敤杩欎簺鏂规硶銆
棣栧厛闇瑕佸湪
cargo.toml
涓坊鍔 web-sys 鐨勪緷璧栵紝骞跺0鏄庨渶瑕佺敤鍒扮殑鐗规э細[dependencies]
wasm-bindgen = "0.2.84"
[dependencies.web-sys]
version = "0.3.64"
features = ["console"]
杩欐牱鍦ㄤ笅娆$紪璇戠殑鏃跺欙紝cargo 灏变細鑷姩澶勭悊杩欎簺渚濊禆锛屽皢浼氫笅杞藉苟鏋勫缓銆
鐒跺悗鍦ㄦ垜浠殑 Rust 鏂囦欢涓紝鍔犲叆瀵 web-sys 鐨勫紩鐢細
extern crate web_sys;
灏卞彲浠ヨ皟鐢 javascript 鐨 console 涓嬬殑鏂规硶浜嗭細
// 璋冪敤console.log
web_sys::console::log_1(&JsValue::from(logContent));
// 璋冪敤console.time(label)
web_sys::console::time_with_label(label);
// 璋冪敤console.timeEnd(label)
web_sys::console::time_end_with_label(label);
鍘 javascript 鐗堟湰浼樺寲妯″瀷鑰楁椂锛
wasm 鐗堟湰浼樺寲妯″瀷鑰楁椂锛
鎬荤粨
浠ヤ笂涓烘牴鎹畼缃戞枃妗f妸妯″瀷鍚堝苟椤剁偣浼樺寲鏂规硶杩佺Щ涓 wasm 鐗堟湰鐨勫紑鍙戠粡鍘嗭紝浠庡畨瑁呭伐鍏峰埌鍙戝竷銆佽皟璇曠殑鏁翠釜杩囩▼銆
涓棿鍥犱负瀵 Rust 鏁版嵁绫诲瀷鐨勪笉鐔熸倝鍜屽涓嶅悓鍓嶇鏋勫缓宸ュ叿瀵 wasm 缁勪欢澶勭悊鐨勪笉鍚屼笉澶熸竻鏅帮紝鍦ㄥ紑鍙戣繃绋嬩腑閬囧埌鐨勯棶棰樺拰瑙e喅鏂规硶銆
Rust 鐗堟湰鐨勪唬鐮侀昏緫鍩烘湰涓婃槸浠 javascript 鐗堟湰缈昏瘧杩囨潵鐨勶紝鍏朵腑搴旇杩樻湁鍦 Rust 鐜涓嬬殑浼樺寲鎵嬫锛屽皢鍦ㄤ箣鍚庣殑瀛︿範涓户缁凯浠c
寮曠敤
[1]Rust 瀹樻柟鏂囨。: https://doc.rust-lang.org/book/
[2]
Rust Wasm 瀹樻柟浠嬬粛鏂囨。: https://rustwasm.github.io/docs/book/
[3]
wasm-pack 瀹樻柟鏂囨。: https://rustwasm.github.io/docs/wasm-pack/
鈴2023 骞 9 鏈 23 鏃ヰ煂熼様鍒 5 骞达紝婧愬垱浼氶噸鍥炴垚閮斤紒馃専鍓嶆部鎶鏈垎浜 + 澶у瀷浜ゆ祦娲诲姩 + 绮剧編鑼舵瓏绀肩墿锝烉煂熷揩鎵弿娴锋姤浜岀淮鐮佹姤鍚嶅惂锛
寰鏈熸帹鑽
JDK 21 GA锛岃櫄鎷熺嚎绋嬫寮忕ǔ瀹氾紒浣犺繕鍧氬畧Java8锛熷墠绔柊杞瓙Nue锛屽彿绉版浛浠ue銆丷eact鍜孲velteJS涓夊ぇ杩愯鏃跺姣旓細Deno銆丅un鍜孨ode.js
杩欓噷鏈夋渶鏂板紑婧愯祫璁佽蒋浠舵洿鏂般佹妧鏈共璐х瓑鍐呭
鐐硅繖閲 鈫撯啌鈫 璁板緱 鍏虫敞鉁 鏍囨槦猸 鍝