Serverless的未来WASM

2021-11-07  本文已影响0人  大哥你先走

1 什么是WASM

WASM是WebAssembly的缩写,WebAssembly是一种用于基于堆栈虚拟机的二进制指令格式。Wasm 被设计为编程语言的可移植编译目标,支持在Web上为客户端和服务器应用程序服务部署。总结起来WASM是一种可以在现代Web浏览器种运行的新型代码,是一种类似低级汇编的语言,拥有紧凑的二进制格式,能够以接近本机的性能运行。为高级语言(C/C++、Go、Rust、Python等)提供编译目标,通过这种方式Rust编写的程序就可以在Web中运行。WASM和JS可以一起配合工作。

2 WASM的特点

2.1 高效快速

WASM非常的轻量且加载速度极快。WASM的目标是以原生的速度运行,从而充分利用各种平台都拥有的通用硬件能力。使用最常见、最普通的硬件提升软件运行的效率。

2.2 安全

WebAssembly 描述了一个内存安全的沙箱执行环境,甚至可以在现有的 JavaScript 虚拟机中实现。当嵌入到 Web 中时,WebAssembly 将强制执行浏览器的同源和权限安全策略。

2.3 开放可调试

WebAssembly 旨在以文本格式漂亮地打印调试信息,用于调试、测试、实验、优化、学习、教学和手工编写程序(这个有点酷)。在网络上查看 Wasm 模块的源时将使用文本格式(这简直是调试的魔法糖)。

2.4 开放Web平台的一部分

WebAssembly 旨在保持 Web 的无版本、功能测试和向后兼容的特性。WebAssembly 模块能够在JavaScript上下文内外调用,可以访问浏览器的函数。WebAssembly也支持在非浏览器环境运行。

3 WSAI

WASM如此的优秀,伟大的程序员当然不想WASM只能在Web中得到应用,WASM应该在任何系统、设备上得到应用,为此设计了WASM的模块化系统接口WASI,通过标准的接口和主机环境进行交互。

4 运行时

WASM的执行依赖运行时环境,目前字节联盟开发了单机的轻量化运行时wasmtime。wasmtime非常的轻巧,Windows下大小只有2MB左右。

wasmtime的主要特点包括:

轻量:WASM的单机运行时,可按需扩展。微信芯片和大型服务器都是无缝使用。可内嵌到大多数的应用程序。因为轻量可以无处不在。

:建立在优化的 Cranelift 代码生成器之上,可以在运行时快速生成高质量的机器代码。

可配置:无论您需要提前预编译您的 wasm 还是在运行时解释它,Wasmtime 都能满足您执行 wasm 的所有需求。

WASI支持:支持丰富的API集合,通过WASI标准和主机环境交互。

标准:Wasmtime 通过了官方的 WebAssembly 测试,实现了 wasm 的官方 C API,也实现了未来对 WebAssembly 的提案。 Wasmtime 开发人员也一直密切参与 WebAssembly 标准流程。

5 快速体验

5.1 使用Rust编写WASM

可以使用rust工具将rust源码编译为wasm,所以我们可以用Rust语言编写程序,然后编译成wasm格式,然后使用wasmtime运行wasm或者在其他语言比如Go中运行wasm,这听起来是不是很酷,下面以一个简单的程序进行说明。

第一步:将WebAssembly设置为cargo编译的目标对象

rustup target add wasm32-wasi

第二步:创建一个简单的Rust项目

cargo new hello-wasm

将main.rs函数修改为如下:

fn main() {
    println!("Hello, WASM")
}

第三步:将Rust代码编译成WASM

cargo build --target wasm32-wasi

在hello-wasm/target/wasm32-wasi/debug目录下可以找到编译后的文件hello-wasm.wasm

5.2 使用wasmtime运行wasm

在hello-wasm.wasm所在的目录打开命令行,执行下面的命令运行wasm:

wasmtime hello-wasm.wasm

屏幕上将会正确打印:Hello, WASM

检查wasmtime是否正确安装

下面我们按照WASM的规范编写一个计算最大公约数gcd的函数,然后使用多种熟悉的编程语言去调用gcd函数。

gcd.wat的内容如下:

(module
  (func $gcd (param i32 i32) (result i32)
    (local i32)
    block  ;; label = @1
      block  ;; label = @2
        local.get 0
        br_if 0 (;@2;)
        local.get 1
        local.set 2
        br 1 (;@1;)
      end
      loop  ;; label = @2
        local.get 1
        local.get 0
        local.tee 2
        i32.rem_u
        local.set 0
        local.get 2
        local.set 1
        local.get 0
        br_if 0 (;@2;)
      end
    end
    local.get 2
  )
  (export "gcd" (func $gcd))
)

5.3 使用Rust运行gcd函数

第一步:创建gcd项目

cargo new gcd

第二步:添加依赖

[dependencies]
wasmtime = "0.31.0"
anyhow = "1.0.45"

第三步:编写main.rs代码运行gcd函数

use anyhow::Result;
use wasmtime::*;

fn main() -> Result<()> {
    let mut store = Store::<()>::default();
    let module = Module::from_file(store.engine(), "gcd.wat")?;
    let instance = Instance::new(&mut store, &module, &[])?;

    let gcd = instance.get_typed_func::<(i32, i32), i32, _>(&mut store, "gcd")?;

    println!("gcd(6, 27) = {}", gcd.call(&mut store, (6, 27))?);
    Ok(())
}

第四步:运行程序查看输出结果

cargo run

程序将会输出:

gcd(6, 27) = 3

5.4 使用Bash运行wasm

第一步:编写gcd.sh运行gcd函数

#!/bin/bash

function gcd() {
  # Cast to number; default = 0
  local x=$(($1))
  local y=$(($2))
  # Invoke GCD from module; suppress stderr
  local result=$(wasmtime gcd.wat --invoke gcd $x $y 2>/dev/null)
  echo "$result"
}

# main
for num in "27 6" "6 27" "42 12"; do
  set -- $num
  echo "gcd($1, $2) = $(gcd "$1" "$2")"
done

第二步:运行gcd.sh

sh gcd.sh

程序将会输出:

gcd(27, 6) = 3
gcd(6, 27) = 3
gcd(42, 12) = 6

5.5 使用Python运行gcd

第一步:安装wasmtime

pip install wasmtime

第二步:编写gcd.py代码运行gcd函数

from wasmtime import Store, Module, Instance

store = Store()
module = Module.from_file(store.engine, 'gcd.wat')
instance = Instance(store, module, [])
gcd = instance.exports(store)["gcd"]

print("gcd(6, 27) = %d" % gcd(store, 6, 27))

第三步:运行gcd.py

python gcd.py

程序将会输出:

gcd(6, 27) = 3
上一篇下一篇

猜你喜欢

热点阅读