5.webassembly和js的小实验
我利用Emscripten和Chrome完成了几个小实验,在一开始我的设想是用C++来完成这些实验的,但是发现JS调取不到我写的函数,我找到两个原因,一个是emscripten在优化的时候会自动把没有用到的函数删除,所以我们需要在emcc的时候把函数添加进去
./emcc -s EXPORTED_FUNCTIONS="['_main', '_my_func']" ...
或者在代码里面这样定义函数
void EMSCRIPTEN_KEEPALIVE yourCfunc() {..}
另外C++的函数因为在编译的时候会更改函数名(我搜索过编译完成的JS文件,函数名给添加了几个字母进去)在这一方面官网似乎也没有解决办法,只是建议使用C函数,所以最后我只能写了C函数做测试,值得一提的是,我在C函数里面用了printf但是并没有成功执行到chrome的控制台里,在main里面执行是有打印的,如果你知道为什么,请在评论下告诉我,谢谢。
接下来我介绍一下我的几个小实验,采用的是EMCC O2的优化(O3会报错),直接编译成JS胶着代码,而不是WASM,采取的是JS调取函数的方式,下一次实验我会用共享内存的方式
在一开始我写了一个这样的函数
void calcuateFun() {
for(int a=0;a<99999999;a++)
{
int c=a*a;
}
}
我通过获取函数调用前以及调用后的js时间戳来得知它的执行情况,同时在原生JS代码中写入相同的函数来做对比,但我非常尴尬的发现执行时间是0毫秒,而原生JS需要几百毫秒,我认为这并不是真实的情况,wo 所以我又写了下面的这个函数
int calcuateFun() {
int c=0;
for(int a=0;a<99999999;a++)
{
c=a*a;
}
return c;
}
但是当我在js用
var a=_calcuateFuneee();
console.log("aaaaa:"+a)
的时候,是可以成功打印出a的,证明函数是有执行的,但是时间为0我认为并不科学,所以我认为是emscripten编译器在执行代码前就优化了代码,在还没有执行前就已经把计算结果处理好了,导致了执行时间为0,在这种情况下可以完爆JS,但并不是我想知道的结果。
我又写了这样的一个函数进行测试
int calcuateFuneee(int cccc) {
int b=999;
double c=cccc;
for(int a=0;a<c;a++)
{
c+=cccc/c;
}
return c;
}
因为这个函数需要传入一个变量计算,编译器不可能在执行前就得知运算结果,除以c是为了防止过大,过大的情况下js会打印出一个负数,同时我在js代码里面写入了一个相同的函数,传了一个比较大的值进去,这是某一次的运算结果,调用C代码用了125毫秒,而JS代码用了131毫秒,几乎看不到差距
我又换了另一种传值方法
for(var a=0;a<10000;a++)
{
var c=_calcuateFuneee(a);
}
在JS里面我用了这样子去调用,这时候webassembly花费的时间甚至比JS还多643:623,这证明了在调用C函数的时候会消耗大量性能,好吧,接下里我试了一下使用EMSCRIPTEN_BINDINGS来调用 发现时间稍微快了点 和JS调用的时间比大概是613:636
最后 我使用了共享内存的方式去调用,时间比是247:633,大概有三倍的提速,必须强调的是,这个结果是在排除了所有干扰后得出的,在纯计算的领域上这应该算是让人兴奋的了,但是实际上要把结果转成数据流这些都会消耗一定性能,但这些相信在未来是可以克服的