天天看點

Node.js中的WebAssembly入門

Node.js中的WebAssembly入門

WebAssembly是一種令人興奮的新語言,許多JavaScript引擎都支援它。WebAssembly有望使編譯C和C ++等語言變得更容易在浏覽器中運作。不過,我最興奮的是能夠編寫優化的自定義算術和緩沖區操作,比如JavaScript中的快速十進制浮點運算,而無需等待TC39來解決。在本文中,我将向您展示如何獲得幾個在Node.js中運作的基本WebAssembly示例,并運作幾個簡單的基準測試來顯示性能影響。

注意:本文中的代碼僅在帶有

--expose-wasm

标志的節點7.2.1上進行了測試。該代碼将不能在節點6.x或節點7.6.0工作,并将不會沒有工作

--expose-wasm

标志。

什麼是WebAssembly無論如何?

--expose-wasm

标志可讓您通路

Wasm

具有用于建立WebAssembly 子產品的多個輔助函數的全局對象。就本文而言,WebAssembly子產品僅是WebAssembly中編寫的函數的集合。

$ ~/Workspace/node-v7.2.1-linux-x64/bin/node --expose-wasm
> Wasm
{ verifyModule: [Function],
  verifyFunction: [Function],
  instantiateModule: [Function],
  experimentalVersion: 11 }
>
           

要建立WebAssembly子產品,您需要

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子產品包括将正确的十六進制數字放入

instantiateModule()

函數中。這些十六進制數字意味着什麼?這些十六進制數字是每個檔案開頭的序言

.wasm

.wasm

是WebAssembly檔案的規範擴充)。每個WebAssembly檔案都必須包含這些位元組,是以這是最小可行的WebAssembly子產品。

添加兩個數字

謝天謝地,你不必自己寫位元組。有很多編譯器用于編譯C,C ++甚至Rust到WebAssembly。還有一種稱為“WebAssembly AST” 的中間格式,簡稱“wast”。這是一個函數,傳回它的2個參數的總和看起來像wast:

(module
  (func $addTwo (param i32 i32) (result i32)
    (i32.add
      (get_local 0)
      (get_local 1)))
  (export "addTwo" $addTwo))
           

你可以使用這個線上工具将代碼編譯成

wasm

二進制代碼,或者你可以直接從我編譯

.wasm

下載下傳。

接下來,你如何

.wasm

在Node.js中使用檔案?為了使用它

.wasm

,你需要加載檔案并将節點的庫傳回的Node.js緩沖區

fs

轉換為ArrayBuffer。

const fs = require('fs');
const buf = fs.readFileSync('./addTwo.wasm');
const lib = Wasm.instantiateModule(new Uint8Array(buf)).exports;

console.log(lib.addTwo(2, 2)); // Prints '4'
console.log(lib.addTwo.toString()); // Prints 'function addTwo() { [native code] }'
           

addTwo

WebAssembly與普通的舊JavaScript實作相比有多快?這是一個簡單的基準:

const fs = require('fs');
const buf = fs.readFileSync('./addTwo.wasm');
const lib = Wasm.instantiateModule(new Uint8Array(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;
}
           
$ ~/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與普通的老JS沒有任何性能上的好處。讓我們做一些更複雜的事情:遞歸地計算因式分解。這是一個

.wast

公開一個

fac()

遞歸計算階乘函數的檔案。

(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))
           

你可以使用這個工具)編譯

.wasm

或隻是在這裡下載下傳它。

下面是将計算

100!

與WebAssembly和JavaScript 進行比較的另一個微不足道的基準:

const fs = require('fs');
const buf = fs.readFileSync('./factorial.wasm');
const lib = Wasm.instantiateModule(new Uint8Array(buf).buffer).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;
  }
  // `x | 0` rounds down, so `2.0001 | 0 === 2`. This helps deal with floating point precision issues like `0.1 + 0.2 !== 0.3`
  return (n * fac(n - 1)) | 0;
}
           
$ ~/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
$
           

繼續

在這些基本的例子中,WebAssembly在允許您真正優化JS代碼方面顯示出了承諾。我的基準測試非常簡陋,WebAssembly仍然不穩定,并且采用不好,是以不要急于嘗試編寫下一個Web應用程式。然而,現在是玩WebAssembly的時候了,尤其是因為它可以在Node.js中使用。

原文位址http://thecodebarbarian.com/getting-started-with-webassembly-in-node.js.html

繼續閱讀