十分钟搞懂 WebAssembly

简介: 十分钟搞懂 WebAssembly

WASM 支持将 C/C++/Go/Rust 等语言实现的代码编译为浏览器可执行的机器码,从而支持浏览器以接近原生应用的性能运行相关应用。在边缘计算领域,WASM 也在尝试建立自己的用例,为边缘应用提供统一的运行环境。原文:Introduction to WebAssembly (WASM)[1]


WebAssembly 于 2015 年首次发布,第一次演示是在 Firefox、Chrome 和 Edge 上执行 Unity 的 Angry Bots 游戏。但仅仅过了 4 年,它就成为了官方标准,是继 HTML、CSS 和 JavaScript 之后的第四种 Web 语言。到目前为止,94%的浏览器已经支持了 WebAssembly。它能够在浏览器中实现接近本机的执行速度,使得我们有可能将桌面应用(如 AutoCAD)甚至电子游戏(如《Doom 3》)移植到 Web。


如今几乎每个人都在谈论 WebAssembly。这篇文章将带你了解什么是 WebAssembly 以及它是如何工作的。


image.png

JavaScript 有什么问题?什么是 WebAssembly?这是一种类似于 C/C++那样的新的编程语言吗?WebAssembly 是如何工作的?WASM 是 Web 应用的未来吗?


我们将回答所有这些问题,并鼓励你开始使用 Web 汇编(web assembly),它有可能极大的改变我们今天所知道的网站!


所以,做好准备,让我们开始吧!⚡


JavaScript 有什么问题?


image.png

Javascript 不是为高性能而开发的


JavaScript 是由 Brenden Eich 在 1995 年为 Netscape 浏览器设计的,在那个年代,它可以为静态网页实现一些交互。


JavaScript 是解释型语言,也是动态类型语言。如果变量类型是在运行时决定的,那么就是动态类型语言。那么动态类型语言的问题是什么呢?


相对于动态类型语言,还有静态类型语言,C++就是一种静态类型语言,其变量类型是在定义的时候就决定了的。


int x = 5 ;


通过一条指令,编译器就能知道变量 x 的类型和内存位置。但是对于 JavaScript 中相同的操作,每次执行程序时,引擎都必须检查它是整数还是浮点数,或者任何其他有效的数据类型。所以 JavaScript 中的每条指令都要经过几次类型检查和转换,这会影响到它的执行速度。


下面是 JavaScript 在运行代码时花费的时间🤓。

image.png

Javascript


下面是 WebAssembly 花费的时间。

image.png

WebAssembly


与 JavaScript 相比,WebAssembly 简化了整个编译过程。


JavaScript 不是为 CPU 密集型和高性能应用程序开发的。


什么是 WebAssembly?


浏览器只能运行 JavaScript,但如果我们有一个虚拟微处理器,它可以将任何高级语言转换成可以在所有主流浏览器上运行的机器码,那会怎么样呢?这正是 Web 汇编(web assembly)所做的事情。


下面是一个用 C++编写并被转为 WASM 的加法函数的例子。


VirtualProcessor 原理图,它将 C++代码转换为浏览器可理解的二进制代码。


image.png



这是一种类似于 C/C++那样的新的编程语言吗?


image.png

确切地说,WASM 不是一种编程语言


WASM 不是一种编程语言🙂。简而言之,它是一种将用一种编程语言编写的代码转换为浏览器可理解的机器代码的技术。


WASM (WebAssembly 的缩写)被设计为其他语言的编译目标,允许服务器端代码(如 C 或 C++代码)被编译成 WASM 并在浏览器中执行。


image.png



WebAssembly 是如何工作的?


要了解 Web 汇编(web assembly),我们首先需要了解什么是通用汇编(general assembly)。


什么是汇编语言和汇编程序?


  • 每个处理器都有一个类似 x86 或 ARM 的架构。此外,处理器只能理解机器码。
  • 编写机器码是件乏味的事情,所以我们用汇编语言来编写。
  • 汇编程序将汇编语言中的指令转换为处理器能理解的机器码。


以下表示了用 C 语言编写的应用程序是如何在你的电脑上运行的。


image.png


类似于通用汇编,在 WebAssembly 中,用高级语言(如 C++)编写的代码被转换为浏览器可理解的机器码。


WebAssembly 入门


WebAssembly 是一个具有 WASM 扩展名的文件,可以把它看作一个可以导入 JavaScript 程序的模块。


项目目录中的交互文件


image.png


记住,WASM 不能直接与 DOM 交互,因此我们需要同时使用 JavaScript 和 WASM。


从上面的讨论中,我们了解到,我们可以在浏览器中运行 C、C++等语言实现的应用程序,其性能接近原生应用。为了实现这一目标,我们需要采取以下步骤。🖖


1. 用你喜欢的语言编写应用程序。


我们编写一个小型 C++函数,用来查找 Fibonacci 数列的第 n 个元素。


// Following is a function that finds nth fibonacci written in C++
int fib(int n)
{
   if (n <= 1)
      return n;
   return fib(n-1) + fib(n-2);
}


2. 创建 WASM 模块。

现在,我们需要将 C++文件转换为浏览器能够理解的预编译 WASM 模块。


有多种方法可以将高级语言代码转换为 WASM。但在本教程中,我们将使用 Web Assembly Explorer[2]


步骤 1:复制粘贴 C++代码,然后点击编译(compile)。

步骤 2:点击汇编(assemble)。

步骤 3:下载 wasm 文件。


image.png

编译和汇编之后(步骤 1,步骤 2)


将下载的文件复制粘贴到项目目录,命名为“math.wasm”。

3. 分发模块——通常可以使用 CDN 实现低延迟分发,但在这个演示中,我们只在本地运行 WASM 文件。


创建script.js,暂时存为空文件。


你的项目目录应该如下所示。


image.png

项目目录视图

4. 加载 WASM 模块


我们将创建loadWebAssembly()函数将给定文件转换为数组缓冲区。然后,该二进制数组缓冲区可以被转换为 WebAssembly 模块。创建数组缓冲区的需求与 Web 汇编内存[3]有关。浏览器可以读取该模块实例。


你的script.js看起来差不多像这样。


let math;
// Let's create a function called loadWebAssembly that converts given file into binary array buffer.
function loadWebAssembly(fileName) {
  return fetch(fileName)
    .then(response => response.arrayBuffer())
    .then(buffer => WebAssembly.compile(buffer)) // Buffer converted to Web Assembly 
    .then(module => {return new WebAssembly.Instance(module) }); // Instance of Web assmebly module is returened 
};   
//We call the function for math.wasm for the given Instance. 
loadWebAssembly('math.wasm')
  .then(instance => {
  }); 


5. 创建模块实例。


下面是最棘手的部分,我们需要在 JS 文件中引用 C++创建的函数。我们不能直接引用这些函数,而是需要使用在 WASM 文件中生成的名字,这些名字定义在 Web Assembly Explorer 的 WAT 列中。


使用下图中带下划线的函数名。


image.png

要引用的变量加了下划线


在你的 WAT 文件中,名字可能不一样。


script.js中,第 1 部分是关于加载 WASM 文件。

第 2 部分提供了一些简单的 javascript 函数,用于比较 javascript 和 WebAssembly 的性能。🤓


//---------------------------PART 1--------------------------------------------------------
// Let's create a function called loadWebAssembly that converts given file into binary array buffer.
function loadWebAssembly(fileName) {
  return fetch(fileName)
    .then(response => response.arrayBuffer())
    .then(buffer => WebAssembly.compile(buffer))
    .then(module => {return new WebAssembly.Instance(module) });
};   
//We call the function for math.wasm
loadWebAssembly('math.wasm')
  .then(instance => {
  fibc = instance.exports._Z3fibi;
    console.log('Call your functions !');
  });
//---------------------------PART 2 -----------------------------------------------
// Function written in Javascript for nth fibonacci 
  function fibj(n)
{
   if (n <= 1)
      return n;
   return fibj(n-1) + fibj(n-2);
}
//This function gives the time required for C++ function
function perfoc(n){
var startTime = performance.now()
var c=fibc(n)
var endTime = performance.now()
console.log(`Calculating nth Fibonacci with WASM took ${endTime - startTime} milliseconds,nth fibonacci is ${c}`)
}
// This function gives the time required for Javascript function
function perfoj(n){
  var startTime = performance.now()
  var j=fibj(n)
  var endTime = performance.now()
  console.log(`Calculating nth Fibonacci with JS took ${endTime - startTime} milliseconds, nth fibonacci is ${j}`)
  }


6. 调用实例函数。

现在可以在本地主机上加载网站并完成演示!


注意:不能直接运行 index.html,因为这样就不会加载 WASM 模块,可以用 Visual Studio Code 的 Live Server 扩展[4]或者 Xampp 拉起本地主机上的项目目录。


转到控制台,我们可以调用以下两个函数。

  1. fibj()→这是用简单的 Javascript 编写的。
  2. fibc()→这是用 C++编写的,然后转换为 WebAssembly。


image.png

两个函数,fibj()和 fibc()


下面是纯 JavaScript 编写的函数(fibj())和从 WebAssembly 导入的函数(fibc())之间的比较。


d393402e3559f83a183af1b18881c327.gif

d3477029f3d19f0e67d243a33ea56e84.gif


WebAssembly 快得多


fibj()fibc()的执行时间是通过以下函数度量的:

  1. perfoj()→告诉我们fibj()所消耗的时间
  2. perfoc()→告诉我们fibc()所消耗的时间


正如我们在上面的 GIF 中所看到的,fibj()(用 JavaScript 编写)所花费的时间比fibc()(用 WebAssembly 编写)要高。


WebAssembly 是 Web 应用的未来吗?


通过 web 汇编,我们可以开发接近原生性能的高性能 web 应用程序,可以执行视频处理、3D 渲染、多媒体游戏、加密计算和 AR/VR 实时应用程序等任务。


因此,基本上,任何需要大量编码和性能优化的应用程序都是 WebAssembly 的完美用例。


你可以自己尝试任何可能性!🧑🔧


本文所有代码在这里:https://github.com/Chandrashekhar-D/Introduction-to-WASM/


参考内容:

官方网站。什么是 WebAssembly?https://webassembly.org/

Mozilla。加载和运行 WebAssembly。https://developer.mozilla.org/en-US/docs/WebAssembly/Loading_and_running

Lin Clark: 用动画介绍 WebAssembly。https://youtu.be/HktWin_LPf4

Guy Royse: WebAssembly 简介 https://youtu.be/3sU557ZKjUs

[5]:Priyesh Patel: JavaScript 到底是如何工作的?https://blog.bitsrc.io/how-does-javascript-really-work-part-1-7681dd54a36d


References:

[1] https://medium.com/dscvitpune/introduction-to-webassembly-wasm-54d505d6d569

[2] https://mbebenita.github.io/WasmExplorer/

[3] https://www.oreilly.com/library/view/webassembly-the-definitive/9781492089834/ch04.html

[4] https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer

目录
相关文章
|
7月前
|
自然语言处理 JavaScript 前端开发
|
9月前
|
JSON 前端开发 JavaScript
探究JavaScript前端热点面试题(三):让你在面试中游刃有余!
探究JavaScript前端热点面试题(三):让你在面试中游刃有余!
|
6月前
|
存储 安全 Linux
从零开始学习DPDK:掌握这些常用库函数就够了(上)
从零开始学习DPDK:掌握这些常用库函数就够了
|
4月前
|
开发框架 移动开发 前端开发
分享47个JavaScript框架源码,总有一款适合您
分享47个JavaScript框架源码,总有一款适合您
30 0
|
4月前
|
开发框架 前端开发 小程序
分享47个PHP框架源码,总有一款适合您
分享47个PHP框架源码,总有一款适合您
70 0
|
6月前
|
存储 缓存 算法
从零开始学习DPDK:掌握这些常用库函数就够了(下)
从零开始学习DPDK:掌握这些常用库函数就够了
|
8月前
|
算法 编译器 程序员
嵌入式C语言代码优化方案(深度好文,建议花时间研读并收藏)
嵌入式C语言代码优化方案(深度好文,建议花时间研读并收藏)
115 0
|
12月前
|
存储 Rust 供应链
编写完10万行代码,我发了篇长文吐槽Rust
编写完10万行代码,我发了篇长文吐槽Rust
133 0