Getting Started With WebAssembly in Node.jsWebAssembly 作为一个门新的语言,已经得到了许多 Javascript 引擎的支持。WebAssembly的目标是为了让 C 和 C++ 这样的编译型语言更容易地在浏览器上运行。…
原文地址: Getting Started With WebAssembly in Node.js
WebAssembly 作为一个门新的语言,已经得到了许多 Javascript 引擎的支持。WebAssembly的目标是为了让 C 和 C++ 这样的编译型语言更容易地在浏览器上运行。而让我感到激动的特性是计算性能和内存操作上的优化,这样让 Javascript 可以实现更为快速的浮点数计算而不用等到 TC39 方案的到来。在这里,借助于 NodeJS 我将会为你展示一些初级的 WebAssembly 示例。并进行一些基本的测试示例来显示其在性能方面的影响作用。
注:文中的所有只在 Node 7.2.1 中进行了测试,并开启了 –expose-wasm参数,其它环境可能无法运行。
通过开启 –expose-wasm参数,在 NodeJS 就可以访问全局对象 Wasm, 通过它可以来创建 WebAssembly 模块。
$ ~/Workspace/node-v7.2.1-linux-x64/bin/node --expose-wasm
> Wasm
{ verifyModule: [Function],
verifyFunction: [Function],
instantiateModule: [Function],
experimentalVersion: 11 }
>
通过 Wasm.instantiateModule() 和 Uint8Array 来创建 WebAssembly 模块。
$ ~/Workspace/node-v7.2.1-linux-x64/bin/node --expose-wasm
> Wasm.instantiateModule(new Uint8Array([0x00, 0x61, 0x73, 0x6d, 0x0b, 0x00, 0x00, 0x00]));
{}
>
为了创建一个最基本的 WebAssembly 模块,你需要传递一组 16进制的数据给 instaniateModule 来得到,如上创建的是一个最小的 WebAssembly 模块,因为每一个 .wasm 文件都必须以这一组16进制数据开始。
两个数字求和
有许多的编译工具可以直接将 C, C++ 和 Rust 代码编译成 WebAssembly,这样我们就不用手写字节码了。也存在一种名为’WebAssembly AST'(简称wast)的中间代码格式,如下为一个简单的支持两个参数的求和函数 wast 代码。
(module
(func $addTwo (param i32 i32) (result i32)
(i32.add
(get_local 0)
(get_local 1)))
(export "addTwo" $addTwo))
你可以使用这个在线工具将 wast 代码转换为 wasm 二进制代码。你也可以直接从这里下载 .wasm源码。
接下来如何用 Node.js 来运行 .wasm 文件呢?为了使用 .wasm文件,你需要通过文件模块将 .wasm 文件转换成 ArrayBuffer 格式。
const fs = require('fs');
const buf = fs.readFileSync('./addTwo.wasm');
const lib = Wasm.instantiateModule(toUint8Array(buf)).exports;
// `Wasm` does **not** understand node buffers, but thankfully a node buffer
// is easy to convert to a native Uint8Array.
function toUint8Array(buf) {
var u = new Uint8Array(buf.length);
for (var i = 0; i < buf.length; ++i) {
u[i] = buf[i];
}
return u;
}
console.log(lib.addTwo(2, 2)); // Prints '4'
console.log(lib.addTwo.toString()); // Prints 'function addTwo() { [native code] }'
上面的 addTwo 方法与原生的 Javascript 方法相比,性能如何呢?如下为我们的测试结果:
const fs = require('fs');
const buf = fs.readFileSync('./addTwo.wasm');
const lib = Wasm.instantiateModule(toUint8Array(buf)).exports;
const Benchmark = require('benchmark');
const suite = new Benchmark.Suite;
suite.
add('wasm', function() {
lib.addTwo(2, 2);
}).
add('js', function() {
addTwo(2, 2);
}).
on('cycle', function(event) {
console.log(String(event.target));
}).
on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').map('name'));
}).
run();
function addTwo(a, b) {
return a + b;
}
function toUint8Array(buf) {
var u = new Uint8Array(buf.length);
for (var i = 0; i < buf.length; ++i) {
u[i] = buf[i];
}
return u;
}
$ ~/Workspace/node-v7.2.1-linux-x64/bin/node --expose-wasm ./addTwo.js
4
wasm x 43,497,742 ops/sec ±0.77% (88 runs sampled)
js x 66,021,200 ops/sec ±1.28% (83 runs sampled)
Fastest is js
阶乘
从上面的例子,我们可以看到 WebAssembly 并没有显示出性能上的优势。接下来我们进行阶乘计算来进一步的测试:
(module
(func $fac (param i32) (result i32)
(if (i32.lt_s (get_local 0) (i32.const 1))
(then (i32.const 1))
(else
(i32.mul
(get_local 0)
(call $fac
(i32.sub
(get_local 0)
(i32.const 1)))))))
(export "fac" $fac))
下面是计算 100!的测试比较结果。
const fs = require('fs');
const buf = fs.readFileSync('./factorial.wasm');
const lib = Wasm.instantiateModule(toArrayBuffer(buf)).exports;
const Benchmark = require('benchmark');
const suite = new Benchmark.Suite;
suite.
add('wasm', function() {
lib.fac(100);
}).
add('js', function() {
fac(100);
}).
on('cycle', function(event) {
console.log(String(event.target));
}).
on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').map('name'));
}).
run();
function fac(n) {
if (n <= 0) {
return 1;
}
return n * fac(n - 1);
}
function toArrayBuffer(buf) {
var ab = new ArrayBuffer(buf.length);
var view = new Uint8Array(ab);
for (var i = 0; i < buf.length; ++i) {
view[i] = buf[i];
}
return ab;
}
$ ~/Workspace/node-v7.2.1-linux-x64/bin/node --expose-wasm ./factorial.js
wasm x 2,484,967 ops/sec ±2.09% (87 runs sampled)
js x 1,088,426 ops/sec ±2.63% (80 runs sampled)
Fastest is wasm
这里我们可以看到,因为计算的复杂度上升,wasm 的优势就显示出来了。
下一步?
从上面的测试例子可以看到通过 WebAssembly 可以很好的优化JS代码,不过这里的测试例子还比较简单,不能覆盖很多的情况,同时 WebAssembly 还并没有推出稳定版本,所以不要莽撞的在应用中使用 WebAssembly。但是我们可以提前试用一下,尤其已经可以在NodeJS中试用了。
原文始发于微信公众号(前端有道):在 NodeJS 中体验 WebAssembly技术(译)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/90292.html