【分享吧】WebAssembly

论坛 期权论坛 程序化     
大连飞创   2018-7-25 17:06   21062   0
什么是 WebAssembly?
  这是由 Google,Microsoft,Mozilla,Apple 等几家大公司合作发起的一个关于 面向Web的通用二进制和文本格式的项目。WebAssembly(又称 wasm) 是一种用于开发网络应用的高效,底层的字节码。它被定义为“精简、加载时间短的格式和执行模型“,并且被设计为Web 多编程语言目标文件格式。 这意味着浏览器端的性能会得到极大提升。当然人们说 WebAssembly 更快的时候,一般来讲是与 JavaScript 相比而言的。
  对二者的比较倒是非常有必要的,这样你就可以了解到 WebAssembly 所拥有的独特特性。
加载时间
  为了加载 JavaScript,浏览器必须加载所有文本格式的 js 文件。
  浏览器会更加快速地加载 WebAssembly,因为 WebAssembly 只会传输已经编译好的 wasm 文件。而且 wasm 是底层的类汇编语言,具有非常紧凑的二进制格式。
执行速度
  当前 Wasm 运行速度只比原生代码慢 20%。这是一个令人惊喜的结果。它是这样的一种格式,会被编译进沙箱环境中且在大量的约束条件下运行以保证没有任何安全漏洞或者使之强化。和真正的原生代码比较,执行速度的下降微乎其微。此外未来它将会更加快速。
  更让人高兴的是,它具备很好的浏览器兼容特性-所有主流浏览器引擎都支持 WebAssembly 且运行速度相差无几(目前IE暂不支持)。
  为了理解和 JavaScript 对比,WebAssembly 的执行速度有多快,你应该首先阅读之前的 JavaScript 引擎工作原理的文章。
  让我们快速浏览下 V8 的运行机制:

V8 技术:懒编译
  左边是 JavaScript 源码,包含 JavaScript 函数。首先,源码先把字符串转换为记号以便于解析,之后生成一个语法抽象树。
  语法抽象树是 JavaScript 程序逻辑在内存中的图示。一旦生成图示,V8 直接进入到机器码阶段。你基本上是遍历树,生成机器码然后获得编译后的函数。这里没有任何真正的尝试来加速这一过程。
  现在,让我们看一下下一阶段 V8 管道的工作内容:

V8 管道设计
  现在,我们拥有 TurboFan ,它是 V8 的优化编译程序之一。当 JavaScript 运行的时候,大量的代码是在 V8 内部运行的。TurboFan 监视运行得慢的代码,引起性能瓶颈的地方及热点(内存使用过高的地方)以便优化它们。它把以上监视得到的代码推向后端即优化过的即时编译器,该编译器把消耗大量 CPU 资源的函数转换为性能更优的代码。
  它解决了性能的问题,但是缺点即是分析代码及辨别哪些代码需要优化的过程也是会消耗 CPU 资源的。这也即意味着更多的耗电量,特别是在手机设备。
  但是,wasm 并不需要以上的全部步骤-它如下所示插入到执行过程中:

V8 管道设计 + WASM
  wasm 在编译阶段就已经通过了代码优化。总之,解析也不需要了。你拥有优化后的二进制代码可以直接插入到后端(即时编译器)并生成机器码。编译器在前端已经完成了所有的代码优化工作。
  由于跳过了编译过程中的不少步骤,这使得 wasm 的执行更加高效。
内存模型
  WebAssembly 可信和不可信状态。
  举个例子,一个 C++ 的程序的内存被编译为 WebAssembly,它是整段连续的没有空洞的内存块。wasam 中有一个可以用来提升代码安全性的功能即执行堆栈和线性内存隔离的概念。在 C++ 程序中,你有一块动态内存区,你从其底部分配获得内存堆栈,然后从其顶部获得内存来增加内存堆栈的大小。你可以获得一个指针然后在堆栈内存中遍历以操作你不应该接触到的变量。
  这是大多数可疑软件可以利用的漏洞。
  WebAssembly 采用了完全不同的内存模型。执行堆栈和 WebAssembly 程序本身是隔离开来的,所以你无法从里面进行修改和改变诸如变量值的情形。同样地,函数使用整数偏移而不是指针。函数指向一个间接函数表。之后,这些直接的计算出的数字进入模块中的函数。它就是这样运行的,这样你就可以同时引入多个 wasm 模块,偏移所有索引且每个模块都运行良好。
内存垃圾回收
  JavaScript 的内存管理是由内存垃圾回收器处理的。
  WebAssembly 的情况有点不太一样。它支持手动操作内存的语言。你也可以在 wasm 模块中内置内存垃圾回收器,但这是一项复杂的任务
  目前,WebAssembly 是专门围绕 C++ 和 RUST 的使用场景设计的。由于 wasm 是非常底层的语言,这意味着只比汇编语言高一级的编程语言会容易被编译成 WebAssembly。C 语言可以使用 malloc,C++ 可以使用智能指针,Rust 使用完全不同的模式(一个完全不同的话题)。这些语言没有使用内存垃圾回收器,所以他们不需要所有复杂运行时的东西来追踪内存。WebAssembly 自然就很适合于这些语言。
  另外,这些语言并不能够 100% 地应用于复杂的 JavaScript 使用场景比如监听 DOM 变化 。用 C++ 来写整个的 HTML 程序是毫无意义的因为 C++ 并不是为此而设计的。大多数情况下,工程师用使用 C++ 或 Rust 来编写 WebGL 或者高度优化的库(比如大量的数学运算)。
  然而,将来 WebAssembly 将会支持不带内存垃圾回功能的的语言。
多线程
  JavaScript 是单线程的。
  JavaScript 也使用 Web Workers 但是只有在极其特殊的情况下-大体上,可以把任何可能阻塞 UI 主线程的密集的 CPU 计算移交给 Web Worker 执行以获得更好的性能。但是,Web Worker 不能够访问 DOM。
  目前 WebAssembly 不支持多线程。但是,这有可能是接下来 WebAssembly 要实现的。Wasm 将会接近实现原生的线程(比如,C++ 风格的线程)。拥有真正的线程将会在浏览器中创造出很多新的机遇。并且当然,会增加滥用的可能性。
可移植性
  现在 JavaScript 几乎可以运行于任意的地方,从浏览器到服务端甚至在嵌入式系统中。
  WebAssembly 设计旨在安全性和可移植性。正如 JavaScript 那样。它将会在任何支持 wasm 的环境(比如每个浏览器)中运行。
  WebAssembly 拥有和早年 Java 使用 Applets 来实现可移植性的同样的目标。
WASM例子

  编写main.c,实现三个方法分别为 main,add,square,并期望在main.html中做相关方法的调用,和数字显示。

  编写main.js

  编写main.html

  执行结果:页面成功调用main.c中的方法。


  查看下main.wasm hexdump的信息

这只是个简单的例子, 代码以上传至github https://github.com/fengchao8627/learnwasm。更多使用场景如下。
WebAssembly 使用场景
  WebAssembly 的最初版本主要是为了解决大量计算密集型的计算的(比如处理数学问题)。最为主流的使用场景即游戏-处理大量的像素。
  你可以使用你熟悉的 OpenGL 绑定来编写C、 C++/Rust 程序,然后编译成 wasm。之后,它就可以在浏览器中运行。
浏览下(在火孤中运行)-http://s3.amazonaws.com/mozilla-games/tmp/2017-02-21-SunTemple/SunTemple.html。这是运行于Unreal engine(这是一个可以用来开发虚拟现实的开发套件)中的。
  另一个合理使用 WebAssembly (高性能)的情况即实现一些处理计算密集型的库。比如,一些图形操作。
  正如之前所提到的,wasm 可以有效减少移动设备的电力损耗(依赖于引擎),这是由于大多数的步骤已经在编译阶段提前处理完成。
  未来,你可以直接使用 WASM 二进制库即使你没有编写编译成它的代码。你可以在 NPM 上面找到一些开始使用这项技术的项目。
  针对操作 DOM 和频繁使用平台接口的情况 ,使用 JavaScript 会更加合理,因为它不会产生额外的性能开销且它原生支持各种接口。
  有了 WebAssembly,我们就可以把大量的数据计算和渲染的工作移交给更加合适的语言来进行处理而把数据收集和 DOM 操作交给 JavaScript 进行处理。


分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3174
帖子:645
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP