WebAssembly,WASM,WASI,WAMR了解

WebAssembly

WebAssembly(wasm) 是一种运行在现代 web 浏览器中的新型代码,并且提供新的性能特性,同时提升了性能。它设计的目的不是为了手写代码,而是为诸如 C、C++ 和 Rust 等源语言提供一个有效的编译目标(就是类似与JAVA的字节码 .class)。

对于 Web 平台而言,这具有巨大的意义——这为客户端 App 提供了一种在 Web 平台以接近本地速度的方式运行多种语言编写的代码的方式;在这之前,客户端 App 是不可能做到的。(简单说,就是客户端App在不重写代码的前提下,移植为Web端)

而且,你在不知道如何编写 WebAssembly 代码的情况下就可以使用它。WebAssembly 的模块可以被导入的到一个 Web App(或 Node.js)中,并且暴露出供 JavaScript 使用的 WebAssembly 函数。JavaScript 框架不但可以使用 WebAssembly 获得巨大性能优势和新特性,而且还能使得各种功能保持对网络开发者的易用性。

深入解释

先说JavaScript的这门语言本身的缺陷。

JavaScript没有静态变量类型。在项目运行的过程中,引擎会对执行次数较多的function记性优化,引擎将其代码编译成Machine Code后打包送到顶部的Just-In-Time(JIT) Compiler,下次再执行这个function,就会直接执行编译好的Machine Code。但是由于JavaScript的动态变量,上一秒可能是Array,下一秒就变成了Object。那么上一次引擎所做的优化,就失去了作用,此时又要再一次进行优化。

WebAssembly就是为解决这个问题诞生的,(asm.js是前身)WebAssembly提升了JavaScript很大的性能,那WebAssembly和JavaScript是什么关系,是协作关系。

由于WebAssembly的诞生,很多应用都有了Web版本,因为1.是Web性能的提升。2.是其他语言(例如c/c++)也可以编译成wasm,不需要代码重写,就可以移植到Web

WASI接口规范

为了让多种语言编译成WebAssembly,并且运行在各种后端上,(无论前端使用的框架是 jQuery 或 vue 或 react , 无论后端使用 java node.js 或者 java 还是 go)必须对多种语言做接口对接规范,这就是WebAssembly System Interface(wasi)

在这里插入图片描述

wasi-sdk

是wasi规范下的wasm编译器,可以把源文件构建为WASM字节码

要安装 WASI SDK,请下载wasi-sdk 版本并将存档解压到默认路径/opt/wasi-sdk

要将源文件构建为 WASM 字节码,我们可以输入以下命令:

/opt/wasi-sdk/bin/clang -O3 -o test.wasm test.c

为什么要在浏览器之外使用WebAssembly?

就像 Javascript 一样,在 WebAssembly 出现后不久,它就不再局限于浏览器。

很多人心中可能有一个疑问:我把C/C++或者Rust程序直接编译成目标机器码就可以了,为什么还要用WebAssembly?这里首先要介绍WebAssembly的沙箱功能。当程序编译成WASM模块,再加载到运行引擎中时,实际上你的模块运行在其私有的沙箱中。沙箱中的程序不能访问沙箱以外的地址空间,否则将被运行引擎终止并返回异常,同时WASM程序调用API来访问系统资源时也会受到运行引擎的监管。这样的沙箱功能可以在许多场景下提供传统的原生编译程序无法支持的功能。

  1. 安全运行第三方代码:这个功能在云端或者边缘计算中非常有意义,也是现代容器技术如Docker的核心价值之一。在移动设备、物联网设备、智能小家电以及可信运行环境上对这样的功能也有非常强烈的需求。
  2. 跨平台与环境的应用:考虑到WebAssembly是由W3C定义的标准化字节文件格式,当某些产品需要提供类似浏览器方式来装载第三方模块时,使用WebAssembly作为媒介格式是一个非常有吸引力的方案。假设你有一个很好的图像识别算法,你可以把你的算法以WASM模块的方式发布。其他人通过集成WAMR这样的引擎就可以在不同架构、不同平台、不同环境调用这个算法,比如在云端容器、可信执行环节(TEE)、物联网设备上都可以调用。
  3. 超轻量级:WASM规范的设计充分考虑了在浏览器上需要通过网络从服务器端下载并即时运行的需求,操作码的设计相当精简。通过开发阶段的编译不再需要对下载程序进行文本解析,实例的对象与内存模型也较为简单。这些特点使WASM模块可以非常快地完成加载进入执行状态,创建一个执行实例只需要很少量的资源。
  4. 高性能:WebAssembly的字节码设计充分考虑了即时编译的友好性,不仅可以达到很快的编译速度,还可以获得很高的运行速度。
  5. 动态模块加载:这个功能在小设备上尤其有用,过去固件必须统一编译、统一更新,如今通过固件中的WASM运行引擎,可以动态加载和执行WASM模块。
  6. 重用海量C/C++库资源: 你也许需要在JS、Java或者Python程序中调用一些C/C++库,传统方式只能使用各种语言自身的绑定接口来集成这些第三方C/C++库。现在我们可以把第三方C/C++库源程序编译成WASM模块,然后通过先绑定WAMR或者其他WASM引擎来执行WASM模块。例如在JVM上通过JNI绑定了WAMR,就不用再使用JNI去绑定其他C/C++库了

字节码联盟

Mozilla、英特尔、RedHat和Fastly公司宣布成立字节码联盟(Bytecode Alliance)

Wasmtime

Wasmtime之前由于Mozilla主导, 现由bytecode alliance接管,Wasmtime是开源的WebAssembly和WASI的小型高效运行时。它在Web外部运行WebAssembly代码,既可以用作命令行实用程序,也可以用作更大应用程序中嵌入的库。

WAMR

WebAssembly Micro Runtime(wamr)最早英特尔公司在GitHub上开源了,现在应该由合作组织字节码联盟进行更新。

也是在浏览器外部运行WebAssembly代码

WAMR项目一开始的设计目标:

  • 菜单式编译框架,支持使用者选择不同的模块、功能和特性编译生成最终产品;
  • 在资源消耗控制方面,WAMR运行引擎的二进制文件在WASM解释器模式下只有85KB,在AoT模式只有50KB。16KB内存就可以跑起来一个WASM小程序,经过一些微调内存消耗甚至可以低至8KB;
  • 在性能方面,WAMR提供了经典(classic)和快速(fast)两个解释器版本,相比常规的Java和JS解释器具有更高的速度。AoT和JIT模式通过LLVM编译框架把WASM生成目标平台的机器指令,能够达到接近GCC编译的速度;
  • AoT模块加载器能支持在Linux、SGX和ZephyrOS上加载预编译到机器指令的WASM模块。

WAMR功能与特性一览

WAMR项目包括以下三部分功能:

  • iwasmVM内核,是WASM字节码的执行引擎,支持解释器、提前编译 (AoT) 和实时编译 (JIT)多种模式;

  • WASM 应用程序API和多实例应用框架;

  • WASM 应用程序的动态管理;

  • WAMR支持许多非常有价值的特性,便于开发者使用,并且支持更广泛的应

场景。主要特性列举如下:

  • 可选择libc支持方案:如果WASM 应用程序需要调用libc的库函数,可以选择基于WASI的标准 libc支持,或者在嵌入式环境中使用内建libc子集支持。开发者可以根据需要选择合适的模式
  • 提供易用的C-API用来嵌入WAMR到宿主程序中
  • 支持将Native API导出到 WASM 应用程序
  • 支持多个WASM模块动态加载与调用
  • 提供线程管理和支持WASM应用使用pthread 库
  • 多架构的支持,目前WAMR已经支持如下多种架构:X86-64、X86-32、ARM、THUMB、AArch64、MIPS、XTENSA
  • 多系统的支持,目前已经支持的系统包括Linux、Zephyr、MacOS、 VxWorks、 AliOS-Things、 Intel Software Guard Extension (Linux)、Android等

WAMR运行模式简介

https://bytecodealliance.github.io/wamr.dev/blog/introduction-to-wamr-running-modes/

WebAssembly(wasm)中,由于其底层是基于字节码的虚拟机,它本身并不支持多线程,但是可以通过JavaScript来实现多线程的功能。具体来说,可以通过Web Worker API来在WebAssembly中开启多个线程。 Web Worker是一种可以在后台运行的JavaScript线程,它可以与其他线程并行工作。通过Web Worker API,我们可以在WebAssembly中创建一个Worker线程,将计算任务分配给Worker线程,从而实现多线程计算。 具体步骤如下: 1. 在主线程中创建一个Worker对象,并将WebAssembly模块传递给Worker线程; 2. 在Worker线程中接收WebAssembly模块,并将其实例化为一个WebAssembly实例; 3. 在Worker线程中定义一个函数,用于接收主线程传递过来的数据,进行计算,并将计算结果返回给主线程; 4. 在主线程中调用Worker线程的postMessage方法,将计算任务传递给Worker线程; 5. 在主线程中定义一个函数,用于接收Worker线程返回的计算结果。 需要注意的是,由于WebAssembly与JavaScript之间的数据传输需要使用TypedArray对象,因此需要保证主线程和Worker线程之间的数据传输类型一致。 下面是一个简单的例子,演示了如何在WebAssembly中开启一个Worker线程: ```javascript // 在主线程中创建一个Worker对象 const worker = new Worker('worker.js'); // 在Worker线程中接收WebAssembly模块,并将其实例化为一个WebAssembly实例 worker.postMessage({ type: 'init', wasmModule: wasmModule }); // 在主线程中调用Worker线程的postMessage方法,将计算任务传递给Worker线程 worker.postMessage({ type: 'calculate', data: data }); // 在主线程中定义一个函数,用于接收Worker线程返回的计算结果 worker.onmessage = function(event) { if (event.data.type === 'result') { // 处理计算结果 } }; ``` 在Worker线程中,我们需要监听message事件,接收主线程传递过来的消息,并根据消息类型进行相应的处理。下面是一个简单的Worker线程示例: ```javascript // 在Worker线程中接收WebAssembly模块,并将其实例化为一个WebAssembly实例 let wasmInstance; onmessage = function(event) { if (event.data.type === 'init') { wasmInstance = new WebAssembly.Instance(event.data.wasmModule); } if (event.data.type === 'calculate') { const data = event.data.data; // 在Worker线程中定义一个函数,用于接收主线程传递过来的数据,进行计算,并将计算结果返回给主线程 const result = wasmInstance.exports.calculate(data); postMessage({ type: 'result', result: result }); } }; ``` 在上面的示例中,我们在Worker线程中定义了一个名为calculate的函数,用于接收主线程传递过来的数据,进行计算,并将计算结果返回给主线程。在实际应用中,需要根据具体的业务逻辑来定义Worker线程中的函数。 需要注意的是,由于WebAssembly目前仍然处于发展阶段,它的多线程支持也在不断改进中,因此在实际应用中需要仔细评估多线程的使用场景和效果。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值