日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

什么是wasm組件?

wasm 全稱 WebAssembly,是通過虛擬機的方式,可以在服務端、客戶端如瀏覽器等環境執行的二進制程序。它有速度快、效率高、可移植的特點。

對我們 Web 前端工程最大的好處就是可以在瀏覽器端使用二進制程序處理一些計算量大的處理,使用他比 JAVA 快的特點優化性能。

目前瀏覽器對wasm的兼容性如下:

https://img10.360buyimg.com/imagetools/jfs/t1/180904/35/36038/170761/64ded9bdF6f54c383/e85e037cdd4fa1fd.jpg

在移動端除了 Android 4.4 和 IOS 10 下不支持外,其他版本都能提供支持。還需要注意的是 wasm 有可能占用大量內存,使用第三方包含 wasm 調用的組件需要注意內存占用防止閃退。

為什么用Rust?

wasm模塊 可以用多種語言來編譯,包括 C/C++/C#、Rust、JAVA、Go。在這里使用 Rust 是因為他有嚴格的內存管理機制,從語法上盡量避免內存溢出,讓工程師寫出更安全的程序。

而且還有配套的工具 wasm-pack,讓使用 Rust 編寫的代碼,編譯包裝成 npm 包,讓使用這段程序的其他代碼可以像使用其他公共庫一樣調用,不需要額外學習成本。

工具安裝

  1. 安裝 rustup,它是 Rust 安裝器和版本管理工具。對于 web 前端來說相當于 nvm 這樣的工具。按照 Rust 官網的方法安裝:https://www.rust-lang.org/zh-CN/tools/install 同時也會安裝 cargo,它是 Rust 的構建工具和包管理器。對于 web 前端來說相當于 npm 這樣的工具。

  2. 安裝 wasm-pack,他是上文提到的把 Rust程序編譯包裝成 wasm 組件的工具。同樣按照 wasm-pack 官網的方法安裝:https://rustwasm.Github.io/wasm-pack/installer/

  3. 使用 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模型的方法,傳入一個模型的頂點信息和距離閾值,比較每個頂點位置之間的距離,如果沒達到閾值距離就合并這兩個頂點,以達到減少頂點的優化目的。

原邏輯是使用 java 編寫的,在模型頂點數量比較多的時候執行的時間比較長。這種大量計算的情況就很適合使用 wasm 來處理。

數據傳遞—

頂點信息是存儲在一個 Float32Array 的數組中的,而 wasm 設計上除了 int 和 float 類型(對應 java 就是 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,

});

}

/*--- java ----*/

// java 傳遞數據到 rust

for(constname ofattributeNames) {

constattr = attrArrays[name]

bg.add_attribute(attr.array, attr.itemSize)

}

而計算后的結果,wasm 也提供了返回數組的指針和數組長度的方法,java 可以讀取 wasm 的內存空間,根據這兩個值構造新的頂點信息Float32Array。

/*--- rust ----*/

// 返回指定數據的內存指針位置

pub fn get_attribute_ptr(&self, index: usize)-> *constf32 {

self.attributes[index].array.as_ptr

}

// 返回指定數據的長度

pub fn get_attribute_length(&self, index: usize)-> usize {

self.attributes[index].array.len

}

/*--- java ----*/

// java 或取 rust 內存空間中的指定部分,構建Float32Array

constptr = bg.get_attribute_ptr(i)

constlength = bg.get_attribute_length(i)

constbuffer = newattr.array.constructor(wasm.getMemory.buffer, ptr, length)

數據類型—

合并頂點計算的邏輯中,有一段是這樣的:每個頂點的位置、UV等信息,經過給定的精度計算后,生成一個特征值,之后比較每個頂點的特征值,如果是相同的話就表示這兩個頂點可以合并。

原 java 版本的代碼是逐個信息按順序,加上分隔號,拼成一個字符串。

Rust版本的代碼如果也按同樣的方法處理,因為頂點的信息量是不定的,有可能只有位置信息,也有可能有UV、法線、顏色等信息,所以生成的特征值字符串長度也不確定。

Rust對於可變長度的字符串使用 String 類型,每次對字符串使用push_str方法增加內容。得到的結果 wasm 版本的執行速度跟 java 版本相差不大,甚至在某些情況下耗時還更多,經過逐個過程作排查,發現是在生成特征值和在表中查詢特征值這個過程中花費的時間比較多。

根據程序的意圖,特征值并不一定要是字符串,只需要在不同輸入值的時候能夠輸出相關的值就可以,這跟生成 hash 值的需求是一樣的,于是考慮將特征值生成替換成 hash 值計算。

因為在存儲特征值的表使用了std::collections::hash_map類型,于是 hash 值也使用了其下的std::collections::hash_map::DefaultHasher類來計算

use std::collections::hash_map::DefaultHasher;

...

let mut hasher = DefaultHasher::new;

forj 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;

需要注意的是對寫入不同類型的內容,需要調用不同的方法,頂點信息中的值是正負值都用,經過精度計算后取整得到的值類型是i32,所以用write_i32來寫入內容。

生成的 hash 值為u64,作為hash_map的key記錄對應頂點的序號。

替換特征值的類型之后,wasm 版本的耗時達到了 java 版本的 1/2,基本符合 wasm 設計的性能范圍。

適配打包工具—

wasm-pack 工具打包出來的 npm 包,可以直接在webpack下加載并調用運行。

我們原本的項目使用 vite 構建,vite 對import wasm 組件策略和 webpack 的不一樣,vite 加載會返回一個加載方法,調用加載方法會返回一個 Promise,resolve 后才會返回跟 webpack 加載一樣的 wasm 組件。

我們要對 wasm-pack 生成的產物作一些修改,假設我們的 wasm 組件命名為 merge_vertice_wasm,生成的主 js 文件應該會命名為merge_vertice_wasm.js,內容如下:

import* aswasm from'./merge_vertice_wasm_bg.wasm'

import{ __wbg_set_wasm } aswasm_bg from'./merge_vertice_wasm_bg.js'

__wbg_set_wasm(wasm);

export* from'./merge_vertice_wasm_bg.js'

為兼容 vite 的加載策略,修改成下面的內容

import* aswasm from'./merge_vertice_wasm_bg.wasm'

import* aswasm_bg from'./merge_vertice_wasm_bg.js'

letmemory

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'

exportfunctiongetMemory() {

returnmemory

}

就可以在 webpack 和 vite 下都可以順利加載并運行了。

其中增加了getMemory的方法供外部獲取 wasm 組件的內存空間。

wasm 調用 java 方法—

當我們在調試和測試性能表現時,需要打印日志,由于我們的 wasm 跑在瀏覽器環境中,我們需要調用 java 的方法,比如console.log和console.time。

wasm-bindgen 庫提供了 web-sys 的組件,讓 Rust可以調用這些方法。

首先需要在cargo.toml中添加 web-sys 的依賴,并聲明需要用到的特性:

[dependencies]

wasm-bindgen = "0.2.84"

[dependencies.web-sys]

version = "0.3.64"

features = ["console"]

這樣在下次編譯的時候,cargo 就會自動處理這些依賴,將會下載并構建。

然后在我們的 Rust文件中,加入對 web-sys 的引用:

externcrate web_sys;

就可以調用 java 的 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);

原 java 版本優化模型耗時:

https://img14.360buyimg.com/imagetools/jfs/t1/109410/21/37527/8537/64dedd1cFe4c8c5c4/596fc2d36cc9fe5c.jpg

wasm 版本優化模型耗時:

https://img12.360buyimg.com/imagetools/jfs/t1/188745/32/36809/10529/64dedd1cF49a8b5cc/8dea820d278ad577.jpg 總結

以上為根據官網文檔把模型合并頂點優化方法遷移為 wasm 版本的開發經歷,從安裝工具到發布、調試的整個過程。

中間因為對 Rust數據類型的不熟悉和對不同前端構建工具對 wasm 組件處理的不同不夠清晰,在開發過程中遇到的問題和解決方法。

Rust版本的代碼邏輯基本上是從 java 版本翻譯過來的,其中應該還有在 Rust環境下的優化手段,將在之后的學習中繼續迭代。

引用

[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/

分享到:
標簽:Rust
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定