最近有一个项目需要以原生方式输出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,需要动态长度数组的不能用。且指针要在js操作完成后才能释放。
传输二维数组的方法:
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
有问题可以相互帮助