1. 程式人生 > >WebAssembly 陣列傳遞(輸出篇)

WebAssembly 陣列傳遞(輸出篇)

最近有一個專案需要以原生方式輸出js陣列,這裡分類一些方法:

公共頭部:

#include <emscripten/val.h>
#include <emscripten/bind.h>

using namespace emscripten;

*注意:在使用emscripten::val和emscripten::bind時,編譯時要帶上--bind引數

耗時對比:

(以傳輸1,580,000個double資料為例,資料單位:毫秒)

方法1:

查閱文件可知,val就是代表的js裡的原生資料型別。

通過val::array()就能構造陣列,通過.set方法可以設定資料內容

所以最初始的辦法就是直接使用for迴圈複製 

val get1XArray(double *arr, int len){
    val ret = val::array();
    for(int i = 0; i < len; i ++) ret.set(i, arr[i]);
	return ret;
}

優點:簡單、直觀、可擴充套件

缺點:記憶體中不連續造成定址時間長

方法2:

上面這種方法由於陣列長度不固定,造成了記憶體浪費,解決方法就是使用TypedArray(對應double的是Float64Array)

查閱文件可知,通過val::global能取得js全域性物件,.new_方法新建例項

改寫後:

val get1XArray(double *arr, int len){
    val ret = val::global("Float64Array").new_(len); //js: new Float64Array(len)
    for(int i = 0; i < len; i ++) ret.set(i, arr[i]);
	return ret;
}

但是這樣速度反而更慢了,可能是因為new操作很耗時

好處是記憶體利用率提高了

方法3:

之後在想辦法解決速度問題時,發現了文件的例項裡有一個typed_memory_view(length, array)函式

(吐槽一下,文件裡沒找到這個函式的解釋,官方文件不認真啊)

所以最終改寫版:

val get1XArray(double *arr, int len){
	return val(typed_memory_view(len, arr));
}

優點:速度上的飛躍,原先需要1200ms才能轉換的資料,現在大概只要7ms

缺點:輸出型別為對應的TypedArray,需要動態長度陣列的不能用

傳輸二維陣列的方法:

val get2XArray(double **arr, int y_len, int x_len){
	val ret = val::array();
	for(int i = 0; i < y_len; i ++){
		ret.set(i, val(typed_memory_view(x_len, arr[i])));
	}
	return ret;
}

另:

因為目前還沒有wasm的群,所以自己建了個:866749590

有問題可以相互幫助