WebAssembly初探记录

1,292 阅读2分钟

由于初次了解WebAssembly,所以对WebAssembly的环境安装以及对基本的c++文件的编写及js的引入进行一次简单的记录

WebAssembly环境安装

  • 安装Emscripten SDK

    参照 webassembly.org.cn/getting-sta… 进行安装,在安装emsdk的过程中如果参照文章提供的以下方式会报错,

    $ git clone https://github.com/juj/emsdk.git
    $ cd emsdk
    $ ./emsdk install sdk-incoming-64bit binaryen-master-64bit
    $ ./emsdk activate sdk-incoming-64bit binaryen-master-64bit
    

    可通过以下安装方式解决

    $ git clone https://github.com/juj/emsdk.git
    $ cd emsdk
    ./emsdk install latest #or ./emsdk install sdk-incoming-64bit binaryen-master-64bit
    ./emsdk activate latest
    
    
  • 安装wabt(The WebAssembly Binary Toolkit--可在字节码和文本格式间相互转换的工具包)

    • 依据github.com/WebAssembly… 按步骤进行安装
    • 配置全局环境变量,进入wabt/bin文件中,输入pwd获取文件夹路径,将路径粘贴在bash_profile中,如下格式:export PATH=/Users/WASM/wabt/bin:$PATH
    • source ~/.bash_profile使得修改立即生效
    • 回到对应的fib文件夹输入wasm2wat fib.wasm -o fib.wat 如果文件夹生成了fib.wat即安装配置成功

c文件代码及引入

1.在fib.c文件写一个不经过优化递归实现的的斐波拉契函数如下

int fib (int n) {
  if (n <= 0) return 0;
  if (n <= 2) return 1;
  return fib(n - 2) + fib(n - 1);
}

2.fib.cpp通过Emscripten编译成fib.wasm文件,通过

emcc fib.c -Os -s WASM=1 -s SIDE_MODULE=1 -o fib.wasm命令生成fib.wasm
SIDE_MODULE = 1
命令解析:https://github.com/emscripten-core/emscripten/wiki/WebAssembly-Standalone
其中注意SIDE_MODULE=1的设置可以使得c文件在编译的时候只编译基本的写法,不会链接libc(C的函数库),
编译出来的wasm文件只有191byte,而如果不设置SIDE_MODULE=1的话fib.wasm将会有10316byte,并且会由于文件过大会导致报错: WebAssembly.Instance is disallowed on the main thread, if the buffer size is larger than 4KB. Use WebAssembly.instantiate.

3.js中引入fib.wasm

function loadWebAssembly(fileName) {
  return fetch(fileName)
    .then(response => response.arrayBuffer()) //加载字节码
    .then(bits => WebAssembly.compile(bits)) //编译字节码
    .then(module => {
      return new WebAssembly.Instance(module) });//实例化
};
  
loadWebAssembly('./fib.wasm')
  .then(instance => {
  	this.$wasmModule = instance.exports; //将instanc暴露在全局变量中以供js调用
    fib = instance.exports.fib;
    console.time();
    console.log('通过调用wasm计算fib(45)', fib(45))
    console.timeEnd();
  });

注意

如果直接打开fib.html会报错: Fetch API cannot load file:///Users/WASM/fib/fib.wasm. URL scheme must be "http" or "https" for CORS request.

原因是通过fetch API获取的本地文件,而fetch API访问的是网络请求即'http' or 'https',而访问的资源是本地文件file:///,所以会由于违反了浏览器同源策略进而报错。

可以通过建立本地服务器的方式解决

1.serve .(需安装serve, yarn global add serve)

2.python2 -m SimpleHTTPServer(需安装python环境)

性能对比

通过本地html引入fib.js文件并打开fib.html; 同时在Chrome浏览器中用js编写递归无优化的斐波拉契函数,两者对比可以发现在计算同样的fib(45)的时候,wasm相较于js在性能上快了将近一倍多。

总结

1.WebAssembly比js快因为通过引入wasm的方式节省了高级代码转变为字节码的时间,即Parser阶段和ByteCode Compiler阶段的时间;

2.在有较大计算量的前端场景下可以通过使用WebAssembly提升性能,在c文件中编写计算量大的函数且通过SIDE_MODULE=1等编译命令编译出独立的wasm模块供js调用

参考文献