日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

理解 Wasm 基礎(chǔ)概念,了解 Wasm 是如何被加載運行的?

來源: 責編: 時間:2023-12-06 09:19:05 260觀看
導讀大家好,我是前端西瓜哥,這次帶大家來簡單系統(tǒng)學習一下 wasm(WebAssembly)。示例源碼在這個 github 倉庫,可自行下載運行:https://github.com/F-star/wasm-demo。wasm 是如何被加載運行的?wasm 文件本身并不能像 JavaScript

nmQ28資訊網(wǎng)——每日最新資訊28at.com

大家好,我是前端西瓜哥,這次帶大家來簡單系統(tǒng)學習一下 wasm(WebAssembly)。nmQ28資訊網(wǎng)——每日最新資訊28at.com

示例源碼在這個 github 倉庫,可自行下載運行:nmQ28資訊網(wǎng)——每日最新資訊28at.com

https://github.com/F-star/wasm-demo。nmQ28資訊網(wǎng)——每日最新資訊28at.com

wasm 是如何被加載運行的?

wasm 文件本身并不能像 JavaScript 一樣,下載完成后就立即執(zhí)行。nmQ28資訊網(wǎng)——每日最新資訊28at.com

它更類似于 webgl 編譯著色器代碼,需要調(diào)用 JavaScript 提供的 API 去編譯執(zhí)行。nmQ28資訊網(wǎng)——每日最新資訊28at.com

wasm 被加載并執(zhí)行的過程一般為:nmQ28資訊網(wǎng)——每日最新資訊28at.com

  • 請求 wasm 文件。
  • 轉(zhuǎn)換為 ArrayBuffer 格式(也就是字節(jié)數(shù)組)。
  • 編譯并返回 Module 對象(異步的,可使用阻塞寫法)。
  • 基于 Module 創(chuàng)建一個 instance 實例(異步的,可使用阻塞寫法) 。instance 的 exports 對象下為 wasm 暴露出來的方法和屬性。創(chuàng)建 instance 有時需要提供一個額外的 importObject 對象,后文再細說。
  • 執(zhí)行 JavaScript 代碼,調(diào)用 wasm 的方法,進行數(shù)據(jù)的交換。

代碼實例:nmQ28資訊網(wǎng)——每日最新資訊28at.com

fetch('./add.wasm')  .then(rep => rep.arrayBuffer()) // 轉(zhuǎn) ArrayBuffer  .then(bytes => WebAssembly.compile(bytes)) // 編譯為 module 對象  .then(module => WebAssembly.instantiate(module)) // 創(chuàng)建 instance 對象  .then(instance => {   // 拿到 wasm 文件暴露的 add 方法    const { add } = instance.exports;    console.log(add(12, 34));  });

上面是為了讓大家理解所有步驟,所以寫得很繁瑣。nmQ28資訊網(wǎng)——每日最新資訊28at.com

我們有簡單寫法,用一個 API 把步驟 1、2、3、4 組合在一起:nmQ28資訊網(wǎng)——每日最新資訊28at.com

WebAssembly.instantiateStreaming(fetch('./add.wasm')).then(res => {  const { module, instance } = res;  const { add } = instance.exports;  console.log(add(12, 34));});

WebAssembly.instantiateStreaming 支持流式編譯,在 wasm 文件下載過程中就開始編譯了,并最后會一次性返回編譯和實例化產(chǎn)生的 module 和 instance 對象。nmQ28資訊網(wǎng)——每日最新資訊28at.com

nmQ28資訊網(wǎng)——每日最新資訊28at.com

wasm 目前現(xiàn)在無法像 ES Module 一樣,通過 import 的方式直接被引入(<script type="module">),將來會支持,且在提案中,但不會很快。nmQ28資訊網(wǎng)——每日最新資訊28at.com

wat:wasm 文本格式

先寫一個 wasm。nmQ28資訊網(wǎng)——每日最新資訊28at.com

原來我打算用 C 寫的,然后用 Emscripten 編譯,但我發(fā)現(xiàn)編譯出來的 wasm 有很多和 C 有關(guān)的冗余的代碼,且需要配合生成好的代碼量巨多的膠水 JavaScript 文件,有不少雜音。nmQ28資訊網(wǎng)——每日最新資訊28at.com

為了更簡單些,我選擇寫 wat,然后轉(zhuǎn)為 wasm。nmQ28資訊網(wǎng)——每日最新資訊28at.com

wat 指的是 wasm 的文本格式(WebAssembly text format)。wat 是一種低級語言,使用的是基于 S-表達式 的文本寫法,可以直接映射為 WASM 的二進制指令,你可以把它類比為匯編語言。nmQ28資訊網(wǎng)——每日最新資訊28at.com

因為用 wat 手寫復雜邏輯并不可行,最后還是會用 C 或 Rust 這些高級語言去寫業(yè)務。nmQ28資訊網(wǎng)——每日最新資訊28at.com

所以這里我不會講太多 wat 語法,目光更聚焦在 探究 wasm 是怎么和 js 通信的。nmQ28資訊網(wǎng)——每日最新資訊28at.com

要實現(xiàn) wat 轉(zhuǎn) wasm,通常需要安裝 WABT(The WebAssembly Binary Toolkit)工具集,用 wat2wasm 命令行工具進行轉(zhuǎn)換。nmQ28資訊網(wǎng)——每日最新資訊28at.com

如果覺得安裝麻煩,可以用 WABT 提供的一個在線轉(zhuǎn)換工具,貼 wat 文本上去點 download 按鈕即可得到 wasm。nmQ28資訊網(wǎng)——每日最新資訊28at.com

nmQ28資訊網(wǎng)——每日最新資訊28at.com

官方有提供 VSCode 插件,建議安裝,可以高亮 wat 語法。nmQ28資訊網(wǎng)——每日最新資訊28at.com

另外可以選中文件右鍵菜單可進行 wat 和 wasm 互轉(zhuǎn),但有點問題,一些正確的 wat 也會轉(zhuǎn)換失敗。nmQ28資訊網(wǎng)——每日最新資訊28at.com

nmQ28資訊網(wǎng)——每日最新資訊28at.com

每次修改完都要手動生成 wasm 可能有點繁瑣,可以考慮安裝 wabt 命令工具,并配合 nodemon 監(jiān)聽 wat 文件,當文件被修改時自動編譯 wasm。nmQ28資訊網(wǎng)——每日最新資訊28at.com

數(shù)字類型

(module  ;; 將兩個 i32 類型的參數(shù)相加返回  (func (export "add") (param i32 i32) (result i32)    local.get 0    local.get 1    i32.add  ))

這里定義了一個 add 方法,接收兩個 i32 類型的參數(shù),相加并返回一個 i32 類型返回值。nmQ28資訊網(wǎng)——每日最新資訊28at.com

wat 使用的棧式機器的方式執(zhí)行的,將兩個參數(shù)依次壓入棧,然后調(diào)用相加運算,這個運算會取出棧頂?shù)膬蓚€數(shù)進行相加,然后把結(jié)果壓入棧。nmQ28資訊網(wǎng)——每日最新資訊28at.com

最后函數(shù)會取棧頂?shù)闹底鳛榉祷刂怠?span style="display:none">nmQ28資訊網(wǎng)——每日最新資訊28at.com

另外,目前 wasm 支持返回多個值了,JavaScript 那邊會得到一個數(shù)組。nmQ28資訊網(wǎng)——每日最新資訊28at.com

;; 是行注釋,另外 (;注釋內(nèi)容;) 是塊注釋。nmQ28資訊網(wǎng)——每日最新資訊28at.com

wasm 的函數(shù)參數(shù)和返回值類型支持的數(shù)字類型有:i32、i64、f32、f64,分別代表 32 位和 64 位的整數(shù)和浮點數(shù)。(還有其他不常用的類型后面再講)nmQ28資訊網(wǎng)——每日最新資訊28at.com

生成 add.wasm 文件,然后再寫一個 js 方法去加載調(diào)用 wasm 的方法:nmQ28資訊網(wǎng)——每日最新資訊28at.com

WebAssembly.instantiateStreaming(fetch('./add.wasm')).then(res => {  const { instance } = res;  const { add } = instance.exports;  console.log(add(100, 34));  console.log(add(100.233, 34)); // 浮點數(shù)被 add 轉(zhuǎn)成整數(shù)了  console.log(add(false, 34)); // true 被轉(zhuǎn)成 1,false 被轉(zhuǎn)成 0  // ...});

查看控制臺輸出:nmQ28資訊網(wǎng)——每日最新資訊28at.com

nmQ28資訊網(wǎng)——每日最新資訊28at.com

js 的數(shù)字只有一種類型:64 位浮點數(shù),調(diào)用 wasm 函數(shù)會進行類型轉(zhuǎn)換,在上面的例子中,add 方法會將其轉(zhuǎn)為 32 位整數(shù)。nmQ28資訊網(wǎng)——每日最新資訊28at.com

此外 js 的非數(shù)值類型也會轉(zhuǎn)為數(shù)字,通常是 0 或 1,字符串的話會嘗試轉(zhuǎn)為數(shù)字(類似調(diào)用 Number())。nmQ28資訊網(wǎng)——每日最新資訊28at.com

wasm 函數(shù)的返回值也會做類型轉(zhuǎn)換為 js 的數(shù)字類型。如果返回的是 i64,在 JavaScript 會轉(zhuǎn)換為 BigInt。nmQ28資訊網(wǎng)——每日最新資訊28at.com

下面是另一種可讀性更好的 wat 寫法。這里給函數(shù)參數(shù)聲明了名字,并給函數(shù)設(shè)置為變量,后面再導出(類似 js 的 export { add })。nmQ28資訊網(wǎng)——每日最新資訊28at.com

(module  ;; 將兩個 i32 類型的參數(shù)相加返回  (func $add (param $a i32) (param $b i32) (result i32)    local.get $a    local.get $b    i32.add)  (export "add" (func $add)))

導入 JavaScript 方法

下面 wat 聲明了需要導入的 JavaScript 方法 a.b()。nmQ28資訊網(wǎng)——每日最新資訊28at.com

(module  ;; wasm 會拿到 importObject 的 a.b 方法  (import "a" "b" (func $getNum (param i32)))  (func (export "getNum")    i32.const 114514    call $getNum ;; 這里把數(shù)字傳給了 importObject 的 a.b 方法  ))

導入的 js 方法需要聲明名稱和函數(shù)簽名。nmQ28資訊網(wǎng)——每日最新資訊28at.com

實例化 module 時提供前面提到的 importObject,去指定這個方法。nmQ28資訊網(wǎng)——每日最新資訊28at.com

const importObject = {  a: {    b: (num) => {      console.log('a.b', num) // 控制臺輸出:“a.b 114514”    }  }}WebAssembly.instantiateStreaming(fetch('./import.wasm'), importObject).then(res => {  const { getNum } = res.instance.exports;  getNum();});

調(diào)用 wasm 定義的 getNum 方法時,該方法會調(diào)用 js 聲明的 a.b() 方法,并傳入一個整數(shù)。nmQ28資訊網(wǎng)——每日最新資訊28at.com

a 是模塊名,b 是這個模塊的一個屬性,模塊屬性除了可以是函數(shù),也可以是其他的類型,比如線性內(nèi)存 memory、表格 table。nmQ28資訊網(wǎng)——每日最新資訊28at.com

我們寫 C 編譯成 wasm,其中的 printf 能夠在控制臺打印出來,就是調(diào)用了導入的 js 的膠水方法,把一些二進制數(shù)據(jù)轉(zhuǎn)換成 js 字符串,然后調(diào)用 console.log()  輸出。nmQ28資訊網(wǎng)——每日最新資訊28at.com

全局變量

將從 importObject.js.global 傳過來的變量作為 wasm 的全局變量。nmQ28資訊網(wǎng)——每日最新資訊28at.com

定義了兩個方法:nmQ28資訊網(wǎng)——每日最新資訊28at.com

  • getGlobal:返回這個全局變量;
  • incGlobal:給全局變量 + 1。
(module  (global $g (import "js" "global") (mut i32))  (func (export "getGlobal") (result i32)    (global.get $g)  )  (func (export "incGlobal")    (global.set $g      (        i32.add        (global.get $g)        (i32.const 1)      )    )  ))

js 中用 new WebAssembly.Global() 創(chuàng)建 global 對象然后導入。nmQ28資訊網(wǎng)——每日最新資訊28at.com

const importObject = {  js: {    // 一個初始值為 233 的 i32 變量    global: new WebAssembly.Global(      {        value: 'i32',        mutable: true,      },      233    ),  },};WebAssembly.instantiateStreaming(fetch('./global.wasm'), importObject).then(  (res) => {    const { instance } = res;    console.log(instance);    const { getGlobal, incGlobal } = res.instance.exports;    console.log('全局變量');    console.log(getGlobal()); // 輸出:233    incGlobal();    incGlobal();    console.log(getGlobal()); // 輸出:235  });

也可以在 js 中直接用 importObject.js.global.value 拿到全局變量的值。nmQ28資訊網(wǎng)——每日最新資訊28at.com

也可以在 wasm 中定義 global 變量,global 變量可以定義多個。nmQ28資訊網(wǎng)——每日最新資訊28at.com

(global $g2 (mut i32) (i32.const 99))

復雜變量類型

wasm 的函數(shù)無法接收和返回一些復雜的高級類型,比如字符串、對象,這時候就需要用到 線性內(nèi)存(memory) 了。nmQ28資訊網(wǎng)——每日最新資訊28at.com

線性內(nèi)存需要用到 WebAssembly.Memory 對象,這個對象是 ArrayBuffer。nmQ28資訊網(wǎng)——每日最新資訊28at.com

nmQ28資訊網(wǎng)——每日最新資訊28at.com

js 和 wasm 共享這個 ArrayBuffer,作為傳輸媒介,然后雙方都在各自的作用域進行序列和反序列化。nmQ28資訊網(wǎng)——每日最新資訊28at.com

這也是 wasm 讓人詬病的通信問題:nmQ28資訊網(wǎng)——每日最新資訊28at.com

如果計算本身的 CPU 密集度不高,那瓶頸就落到數(shù)據(jù)序列化反序列化以及通信上了,別說提升性能了,降低性能都可能。nmQ28資訊網(wǎng)——每日最新資訊28at.com

wat:nmQ28資訊網(wǎng)——每日最新資訊28at.com

(module  (import "console" "log" (func $log (param i32 i32)))  ;; 傳入的 memory 大小為 1 頁  (import "js" "mem" (memory 1))  ;; 在 memory 的地址 0 處設(shè)置數(shù)據(jù) "Hi"  (data (i32.const 0) "Hi")    (func (export "writeHi")    i32.const 0  ;; 字符串起始位置    i32.const 2  ;; 字符串長度    call $log  ))

js:nmQ28資訊網(wǎng)——每日最新資訊28at.com

// memory 對象,大小為 1 頁(page),1 頁為 64 KBconst memory = new WebAssembly.Memory({ initial: 1 });// wasm 無法直接返回字符串,但可以修改線性內(nèi)存// 然后再指定線性內(nèi)存的區(qū)間讓 js 去截取需要的 ArrayBuffer// 最后 ArrayBuffer 轉(zhuǎn) 字符串function consoleLogString(offset, length) {  const bytes = new Uint8Array(memory.buffer, offset, length);  const string = new TextDecoder('utf-8').decode(bytes);  console.log(string);}const importObject = {  console: { log: consoleLogString },  js: { mem: memory },};WebAssembly.instantiateStreaming(fetch('./memory.wasm'), importObject).then(  (res) => {    res.instance.exports.writeHi();  });

也可以在 js 傳字符串給 wasm,但 js 這邊要做字符串轉(zhuǎn) ArrayBuffer 的操作。nmQ28資訊網(wǎng)——每日最新資訊28at.com

下面是拼接兩個字符串返回新字符串示例。nmQ28資訊網(wǎng)——每日最新資訊28at.com

wat:nmQ28資訊網(wǎng)——每日最新資訊28at.com

(module  (import "console" "log" (func $log (param i32 i32)))  (import "js" "mem" (memory 1))  ;; 函數(shù)接受兩個字符串并拼接它們  (func $concatStrings (param $offset1 i32) (param $length1 i32) (param $offset2 i32) (param $length2 i32) (result i32) (result i32)    ;; 這里的代碼是將兩個字符串拼接到內(nèi)存中,并返回新字符串的偏移量和長度    ;; 注意:為了簡單起見,這里假設(shè)你有足夠的內(nèi)存空間來拼接字符串    (local $newOffset i32)    ;; 假設(shè)新的偏移量是在第一個字符串的結(jié)束處    local.get $offset1    local.get $length1    i32.add    local.set $newOffset    ;; 將第二個字符串拷貝到新的偏移量處    local.get $newOffset    local.get $offset2    local.get $length2    memory.copy    ;; 返回新的偏移量和長度    local.get $offset1    local.get $length1    local.get $length2    i32.add  )  (func (export "concatAndLog") (param $offset1 i32) (param $length1 i32) (param $offset2 i32) (param $length2 i32)    ;; 調(diào)用上面的拼接函數(shù)    local.get $offset1    local.get $length1    local.get $offset2    local.get $length2    call $concatStrings    ;; 使用結(jié)果來調(diào)用$log    call $log  ))

js:nmQ28資訊網(wǎng)——每日最新資訊28at.com

const memory = new WebAssembly.Memory({ initial: 1 });function consoleLogString(offset, length) {  // console.log(offset, length);  const bytes = new Uint8Array(memory.buffer, offset, length);  const string = new TextDecoder('utf-8').decode(bytes);  console.log(string); // 輸出 Hello, WebAssembly!}let currentOffset = 0; // 添加這個變量來跟蹤當前可用的內(nèi)存偏移量function stringToMemory(str, mem) {  const encoder = new TextEncoder();  const bytes = encoder.encode(str);  new Uint8Array(mem.buffer, currentOffset, bytes.length).set(bytes);  const returnOffset = currentOffset;  currentOffset += bytes.length; // 更新偏移量  return { offset: returnOffset, length: bytes.length };}const importObject = {  console: { log: consoleLogString },  js: { mem: memory },};WebAssembly.instantiateStreaming(fetch('./concat.wasm'), importObject).then(  (res) => {    const str1 = 'Hello, ';    const str2 = 'WebAssembly!';    const mem1 = stringToMemory(str1, memory);    const mem2 = stringToMemory(str2, memory);    res.instance.exports.concatAndLog(      mem1.offset,      mem1.length,      mem2.offset,      mem2.length    );  });

其他類型也一樣的思路,只要支持轉(zhuǎn)換成 ArrayBuffer,然后轉(zhuǎn)換回來就好了。nmQ28資訊網(wǎng)——每日最新資訊28at.com

一個 wasm 模塊只能定義一個線性內(nèi)存 memory,這個是出于簡單的考量。nmQ28資訊網(wǎng)——每日最新資訊28at.com

表格 table

table 是一個大小可變的引用數(shù)組,指向 wasm 的代碼地址。nmQ28資訊網(wǎng)——每日最新資訊28at.com

前面的 wat 執(zhí)行代碼時,會使用 run 指令接一個 靜態(tài) 的函數(shù)索引。但有時候函數(shù)索引需要是動態(tài),一會指向函數(shù) a,過一段時間又指向 b。nmQ28資訊網(wǎng)——每日最新資訊28at.com

這時候我們就可以使用 table 去維護。nmQ28資訊網(wǎng)——每日最新資訊28at.com

(table 2 funcref)

anyfunc 類型,代表可以是任何簽名的函數(shù)引用。nmQ28資訊網(wǎng)——每日最新資訊28at.com

因為安全問題函數(shù)引用不能保存在線性內(nèi)存(memory)中。因為線性內(nèi)存保存地址沒意義,而存真正的函數(shù)數(shù)據(jù)源有可能被惡意修改,有安全問題。nmQ28資訊網(wǎng)——每日最新資訊28at.com

所以整出了這么一個抽象的 table 數(shù)組,這個 table 無法被讀取真正的內(nèi)容,只能更新一下數(shù)組的引用。nmQ28資訊網(wǎng)——每日最新資訊28at.com

下面是一個示例,在 wat 創(chuàng)建了一個 table,然后讓 js 根據(jù)索引調(diào)用 table 中的動態(tài)引用的函數(shù)。nmQ28資訊網(wǎng)——每日最新資訊28at.com

watnmQ28資訊網(wǎng)——每日最新資訊28at.com

(module  ;; table 大小為 2,且為函數(shù)引用類型。  (table $t 2 funcref)  ;; table 從 0 偏移值填充聲明的兩個函數(shù)  ;; 0 指向 $f1,1 指向 $f2  (elem (i32.const 0) $f1 $f2)  ;; 函數(shù)聲明可以在任何位置  (func $f1 (result i32)    i32.const 22  )  (func $f2 (result i32)    i32.const 33  )  ;; 定義函數(shù)類型,一個返回 i32 的函數(shù)(類比 ts 的函數(shù)類型)  (type $return_i32 (func (result i32)))  ;; 暴露一個 callByIndex 方法給 js  ;; callByIndex(0) 表示調(diào)用 table 上索引為 0 的函數(shù)。  (func (export "callByIndex") (param $i i32) (result i32)    ;; (間接)調(diào)用 $i 索引值在 table 中指向的方法    call_indirect (type $return_i32)  ))

js:nmQ28資訊網(wǎng)——每日最新資訊28at.com

WebAssembly.instantiateStreaming(fetch('./table.wasm')).then((res) => {  const { callByIndex } = res.instance.exports;  console.log(callByIndex(0)); // 22  console.log(callByIndex(1)); // 33});

也可以在 js 中更新 table,讓一些索引指向新的函數(shù)。nmQ28資訊網(wǎng)——每日最新資訊28at.com

但需要注意,這個函數(shù)需要時 wasm 導出,而不是 js 函數(shù)。nmQ28資訊網(wǎng)——每日最新資訊28at.com

下面是對應的示例。nmQ28資訊網(wǎng)——每日最新資訊28at.com

wat:nmQ28資訊網(wǎng)——每日最新資訊28at.com

(module   ;; 導入 table  (import "js" "table" (table 1 funcref))  (elem (i32.const 0) $f1)  (func $f1 (result i32)    i32.const 22  )  (type $return_i32 (func (result i32)))  (func (export "call") (result i32)    i32.const 0    call_indirect (type $return_i32)  )  (func (export "get666") (result i32)    i32.const 666  ))

js:nmQ28資訊網(wǎng)——每日最新資訊28at.com

const table = new WebAssembly.Table({ initial: 1, element: 'anyfunc' });const importObject = {  js: { table },};WebAssembly.instantiateStreaming(  fetch('./outer-table.wasm'),  importObject).then((res) => {  const { call, get666 } = res.instance.exports;  console.log(call()); // 22  console.log(table.get(0)); // 獲取 wasm 函數(shù)  table.set(0, get666); // 更換 table[0] 的函數(shù)。  console.log(call()); // 666});

在 wat 中,anyfunc 是舊寫法,現(xiàn)在換成了 funcref,來表示函數(shù)引用。nmQ28資訊網(wǎng)——每日最新資訊28at.com

不過 js 中創(chuàng)建 table,element 參數(shù)還得傳 "anyfunc"。nmQ28資訊網(wǎng)——每日最新資訊28at.com

table 的這個特性可以實現(xiàn)類似 dll 的動態(tài)鏈接能力,可以在程序運行時才動態(tài)鏈接需要的代碼和數(shù)據(jù)。nmQ28資訊網(wǎng)——每日最新資訊28at.com

引用類型

wasm 的函數(shù)現(xiàn)在支持傳 引用類型(externref)。nmQ28資訊網(wǎng)——每日最新資訊28at.com

(func (export "callJSFunction") (param externref)  ...)

你可以傳任何 js 變量作為 externref 類型傳入 wasm 函數(shù),但該變量在 wasm 不能被讀寫和執(zhí)行,但可以把作為返回值,或是它作為參數(shù)傳給 import 進來的 js 函數(shù)。nmQ28資訊網(wǎng)——每日最新資訊28at.com

wasm 只能對 externref 做中轉(zhuǎn),傳入以及返回回去,無法做任何其他操作。nmQ28資訊網(wǎng)——每日最新資訊28at.com

示例:nmQ28資訊網(wǎng)——每日最新資訊28at.com

(module  (type $jsFunc (func (param externref)))  (func $invoke (import "js" "invokeFunction") (type $jsFunc))    (func (export "callJSFunction") (param externref)    local.get 0    call $invoke  ))
const importObject = {  js: {    invokeFunction: (fn) => {      fn();    },  },};WebAssembly.instantiateStreaming(fetch('./type.wasm'), importObject).then(  (res) => {    const { instance } = res;    const { callJSFunction } = instance.exports;    callJSFunction(() => {      console.log('被執(zhí)行的是來自 js 函數(shù)');    });  });

矢量類型

v128,一個 128 比特的矢量類型。nmQ28資訊網(wǎng)——每日最新資訊28at.com

用于 SIMD(Single Instruction, Multiple Data),它是一種計算機并行處理技術(shù),允許一個單一的操作指令同時處理多個數(shù)據(jù)元素,使用用在大量數(shù)據(jù)執(zhí)行相同操作的場景,比如矩陣運算。nmQ28資訊網(wǎng)——每日最新資訊28at.com

v128 是其他數(shù)據(jù)的打包,打包一起好做并行運行,提高計算速度。nmQ28資訊網(wǎng)——每日最新資訊28at.com

這些數(shù)據(jù)可能是:nmQ28資訊網(wǎng)——每日最新資訊28at.com

  • 4 個 i32(或 f32)
  • 2 個 i64(或 f64)
  • 16 個 i8
  • 8 個 i16

然后它們會使用類似 i32x4 的指令進行批量操作:nmQ28資訊網(wǎng)——每日最新資訊28at.com

i32x4.add (local.get $a) (local.get $b)

雖然沒有 i8 和 i16 這種類型,但它們本質(zhì)是 ArrayBuffer(字節(jié)數(shù)組)的一種高層級,js 那邊可以用 ArrayBuffer 構(gòu)造出 Int8Array 對象。nmQ28資訊網(wǎng)——每日最新資訊28at.com

所以 wat 提供了對應的指令,比如 i8x16.add。nmQ28資訊網(wǎng)——每日最新資訊28at.com

示例:nmQ28資訊網(wǎng)——每日最新資訊28at.com

(module  (memory 1)  (export "memory" (memory 0))  (func (export "add_vectors")    (param $aOffset i32) (param $bOffset i32)    (local $a v128) (local $b v128)    (local.set $a (v128.load (local.get $aOffset)))    (local.set $b (v128.load (local.get $bOffset)))    (v128.store (i32.const 0) (i32x4.add (local.get $a) (local.get $b)))  ))
WebAssembly.instantiateStreaming(fetch('./v128.wasm')).then((res) => {  const { add_vectors, memory } = res.instance.exports;  // 首先在內(nèi)存中分配兩個向量a和b  const a = new Int32Array(memory.buffer, 0, 4);  const b = new Int32Array(memory.buffer, 16, 4);  // 初始化向量a和b的值  a.set([1, 2, 3, 4]);  b.set([5, 6, 7, 8]);  console.log('Vector A:', a);  console.log('Vector B:', b);  // 調(diào)用add_vectors函數(shù),傳入向量a和b在內(nèi)存中的偏移量  add_vectors(0, 16);  // 讀取和打印結(jié)果  const result = new Int32Array(memory.buffer, 0, 4);  console.log('Result:', result); // [6, 8, 10, 12]});

nmQ28資訊網(wǎng)——每日最新資訊28at.com

多線程

wasm 支持多線程。nmQ28資訊網(wǎng)——每日最新資訊28at.com

我們可以使用多個 Web Worker 各自創(chuàng)建 wasm 實例,讓它們共享同一段內(nèi)存 SharedArrayBuffer。nmQ28資訊網(wǎng)——每日最新資訊28at.com

因為多線程特有的競態(tài)條件問題,我們需要用到 Atomics 對象,它提供了一些原子操作,防止沖突。nmQ28資訊網(wǎng)——每日最新資訊28at.com

最后是 wait/notify 進行線程的掛起和喚醒。nmQ28資訊網(wǎng)——每日最新資訊28at.com

這個用的不多,就簡單介紹一下就好了。nmQ28資訊網(wǎng)——每日最新資訊28at.com

結(jié)尾

wasm 是 js 的一個強有力的補充,未來可期,在一些領(lǐng)域比如圖像處理、音視頻處理大有可為。nmQ28資訊網(wǎng)——每日最新資訊28at.com

但也不得不承認 wasm 并不能很簡單地就能給應用提高性能的,因為安全原因,相比原生是有一定性能損失的。nmQ28資訊網(wǎng)——每日最新資訊28at.com

如果沒做正確的設(shè)計甚至因為通信成本導致負優(yōu)化,你需要考量性能的瓶頸在哪里,到底是代碼寫得爛呢還是 CPU 計算就是高。v8 的 JIT 過于優(yōu)秀,導致 wasm 的光芒不夠耀眼。nmQ28資訊網(wǎng)——每日最新資訊28at.com

另外,wasm 有不小的學習成本的。nmQ28資訊網(wǎng)——每日最新資訊28at.com

但不可否認,wasm 是前端的一個大方向,還是有一定學習投入的必要。nmQ28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-38513-0.html理解 Wasm 基礎(chǔ)概念,了解 Wasm 是如何被加載運行的?

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: CSS_Flex 那些鮮為人知的內(nèi)幕

下一篇: 優(yōu)化技巧:如何加快Spring項目啟動速度

標簽:
  • 熱門焦點
  • 一年經(jīng)驗在二線城市面試后端的經(jīng)驗分享

    忠告這篇文章只適合2年內(nèi)工作經(jīng)驗、甚至沒有工作經(jīng)驗的朋友閱讀。如果你是2年以上工作經(jīng)驗,請果斷劃走,對你沒啥幫助~主人公這篇文章內(nèi)容來自 「升職加薪」星球星友 的投稿,坐
  • 三言兩語說透設(shè)計模式的藝術(shù)-單例模式

    寫在前面單例模式是一種常用的軟件設(shè)計模式,它所創(chuàng)建的對象只有一個實例,且該實例易于被外界訪問。單例對象由于只有一個實例,所以它可以方便地被系統(tǒng)中的其他對象共享,從而減少
  • 不容錯過的MSBuild技巧,必備用法詳解和實踐指南

    一、MSBuild簡介MSBuild是一種基于XML的構(gòu)建引擎,用于在.NET Framework和.NET Core應用程序中自動化構(gòu)建過程。它是Visual Studio的構(gòu)建引擎,可在命令行或其他構(gòu)建工具中使用
  • 如何通過Python線程池實現(xiàn)異步編程?

    線程池的概念和基本原理線程池是一種并發(fā)處理機制,它可以在程序啟動時創(chuàng)建一組線程,并將它們置于等待任務的狀態(tài)。當任務到達時,線程池中的某個線程會被喚醒并執(zhí)行任務,執(zhí)行完任
  • 多線程開發(fā)帶來的問題與解決方法

    使用多線程主要會帶來以下幾個問題:(一)線程安全問題  線程安全問題指的是在某一線程從開始訪問到結(jié)束訪問某一數(shù)據(jù)期間,該數(shù)據(jù)被其他的線程所修改,那么對于當前線程而言,該線程
  • 只需五步,使用start.spring.io快速入門Spring編程

    步驟1打開https://start.spring.io/,按照屏幕截圖中的內(nèi)容創(chuàng)建項目,添加 Spring Web 依賴項,并單擊“生成”按鈕下載 .zip 文件,為下一步做準備。請在進入步驟2之前進行解壓。圖
  • 品牌洞察丨服務本地,美團直播成效幾何?

    來源:17PR7月11日,美團App首頁推薦位出現(xiàn)&ldquo;美團直播&rdquo;的固定入口。在直播聚合頁面,外賣&ldquo;神槍手&rdquo;直播間、美團旅行直播間、美團買菜直播間等均已上線,同時
  • iQOO Neo8 Pro即將開售:到手價3099元起 安卓性能最強旗艦

    5月23日,iQOO如期舉行了新品發(fā)布會,全新的iQOO Neo8系列也正式與大家見面,包含iQOO Neo8和iQOO Neo8 Pro兩個版本,其中標準版搭載高通驍龍8+,而Pro版更
  • “買真退假” 這種“羊毛”不能薅

    □ 法治日報 記者 王春   □ 本報通訊員 胡佳麗  2020年初,還在上大學的小東加入了一個大學生兼職QQ群。群主&ldquo;七王&rdquo;在群里介紹一些刷單賺
Top 主站蜘蛛池模板: 荃湾区| 昌江| 都安| 绍兴县| 喀喇沁旗| 鄢陵县| 齐齐哈尔市| 洛隆县| 双鸭山市| 永靖县| 昔阳县| 谢通门县| 万源市| 永修县| 霍州市| 大名县| 徐汇区| 崇义县| 长寿区| 礼泉县| 西平县| 色达县| 庐江县| 灵寿县| 孝感市| 双江| 米脂县| 南华县| 孙吴县| 林周县| 浑源县| 宁都县| 格尔木市| 甘德县| 登封市| 山阴县| 萝北县| 洞口县| 万宁市| 合肥市| 玛多县|