41

WebAssembly运行时--Wasmtime

 3 years ago
source link: https://studygolang.com/articles/30615
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Wasmtime是由 bytecodealliance 开源的WebAssembly和WASI的小型高效运行时。它在Web外部运行WebAssembly代码,既可以用作命令行实用程序,也可以用作更大应用程序中嵌入的库。

uyeAjqY.jpg!mobile

具备以下特点:

  • 轻量级 。Wasmtime是WebAssembly的独立运行时,可根据您的需求进行扩展。它适合于微型芯片,也可以使用大型服务器。 Wasmtime也可以嵌入几乎所有应用程序中。
  • 。Wasmtime建立在优化的Cranelift代码生成器上,可在运行时快速生成高质量的机器代码。
  • 可配置 。无论您是需要提前预编译wasm,使用Lightbeam快速生成代码还是在运行时进行解释,Wasmtime都能满足您执行wasm的所有需求。
  • WASI Wasmtime支持一组丰富的API,用于通过 WASI标准 与主机环境进行交互。
  • 标准 。Wasmtime通过了官方的WebAssembly测试套件,实现了wasm的官方C API,并且还实现了WebAssembly的proposals。 Wasmtime开发人员也一直与WebAssembly标准流程密切相关。

目前支持语言:

  • Rust - the ["https://crates.io/crates/wasmtime">wasmtime crate](https://zhuanlan.zhihu.com/p/224862650/%3C/code)
  • C - the f="https://bytecodealliance.github.io/wasmtime/c-api/">wasm.h, wasi.h, and wasmtime.h headers
  • Python - the ["https://pypi.org/project/wasmtime/">wasmtime PyPI package](https://zhuanlan.zhihu.com/p/224862650/%3C/code)
  • .NET - the ["https://www.nuget.org/packages/Wasmtime">Wasmtime NuGet package](https://zhuanlan.zhihu.com/p/224862650/%3C/code)
  • Go - the [wasmtime-go repository](https://zhuanlan.zhihu.com/p/224862650/ht%3C/code%3Etps://pkg.go.dev/github.com/bytecodealliance/wasmtime-go)

安装

在macos和linux上安装Wasmtime CLI非常简单,只需执行以下命令即可:

$ curl https://wasmtime.dev/install.sh -sSf | bash

Windows或是其他操作系统用户,需要到 GitHub Releases 下载。

由于我的操作系统是centos,所以可能展现的与您有所不同。我执行安装脚本之后,有如下输出:

curl https://wasmtime.dev/install.sh -sSf | bash
  Installing latest version of Wasmtime (dev)
    Checking for existing Wasmtime installation
    Fetching archive for Linux, version dev
https://github.com/cranestation/wasmtime/releases/download/dev/wasmtime-dev-x86_64-linux.tar.xz
######################################################################## 100.0%
    Creating directory layout
  Extracting Wasmtime binaries
wasmtime-dev-x86_64-linux/
wasmtime-dev-x86_64-linux/wasmtime
wasmtime-dev-x86_64-linux/LICENSE
wasmtime-dev-x86_64-linux/README.md
     Editing user profile (/root/.bashrc)
Warning: Your profile (/root/.bashrc) already mentions Wasmtime and has not been changed.
    Finished installation. Open a new terminal to start using Wasmtime!

然后我们检查以下是否成功安装了wasmtime:

# wasmtime
wasmtime 0.19.0
Wasmtime WebAssembly Runtime
USAGE:
    wasmtime <SUBCOMMAND>
FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information
SUBCOMMANDS:
    config      Controls Wasmtime configuration settings
    help        Prints this message or the help of the given subcommand(s)
    run         Runs a WebAssembly module
    wasm2obj    Translates a WebAssembly module to native object file
    wast        Runs a WebAssembly test script file
If a subcommand is not provided, the `run` subcommand will be used.
Usage examples:
Running a WebAssembly module with a start function:
  wasmtime example.wasm
Passing command line arguments to a WebAssembly module:
  wasmtime example.wasm arg1 arg2 arg3
Invoking a specific function (e.g. `add`) in a WebAssembly module:
  wasmtime example.wasm --invoke add 1 2

安装完毕,我们接下来Hello world搞起。

Demo

Wasmtime可作为Go模块使用。接下来介绍如何将Wasmtime添加到您的项目中,并提供一些示例说明可以使用WebAssembly模块完成的操作。

确保您正在使用带有模块支持的Go 1.12或更高版本。

首先创建一个go 模块项目:

$ mkdir hello-wasm
$ cd hello-wasm
$ go mod init hello-wasm

然后编写main.go,具体代码如下:

package main
import (
    "fmt"
    "github.com/bytecodealliance/wasmtime-go"
)
func main() {
    engine := wasmtime.NewEngine()
    // Almost all operations in wasmtime require a contextual `store`
    // argument to share, so create that first
    store := wasmtime.NewStore(engine)
    // Compiling modules requires WebAssembly binary input, but the wasmtime
    // package also supports converting the WebAssembly text format to the
    // binary format.
    wasm, err := wasmtime.Wat2Wasm(`
      (module
        (import "" "hello" (func $hello))
        (func (export "run")
          (call $hello))
      )
    `)
    check(err)
    // Once we have our binary `wasm` we can compile that into a `*Module`
    // which represents compiled JIT code.
    module, err := wasmtime.NewModule(engine, wasm)
    check(err)
    // Our `hello.wat` file imports one item, so we create that function
    // here.
    item := wasmtime.WrapFunc(store, func() {
        fmt.Println("Hello from Go!")
    })
    // Next up we instantiate a module which is where we link in all our
    // imports. We've got one import so we pass that in here.
    instance, err := wasmtime.NewInstance(store, module, []*wasmtime.Extern{item.AsExtern()})
    check(err)
    // After we've instantiated we can lookup our `run` function and call
    // it.
    run := instance.GetExport("run").Func()
    _, err = run.Call()
    check(err)
}
func check(e error) {
    if e != nil {
        panic(e)
    }
}

最后运行:

$ go run main.go
Hello from Go!

当然当我们wasm模块代码比较庞大的时候,我们可以将该代码放到一个以.wat结尾的文件中。然后使用 NewModuleFromFile 函数,从指定wat文件中加载模块代码。

例如:

我们创建以下wasm 文本模块,主要导出用于计算两个数字的最大公分母的函数。命名为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))
)

然后修改我们的main.go文件,如下:

package main
import (
    "fmt"
    "github.com/bytecodealliance/wasmtime-go"
)
func main() {
    engine := wasmtime.NewEngine()
    store := wasmtime.NewStore(engine)
    module, err := wasmtime.NewModuleFromFile(engine, "gcd.wat")
    check(err)
    instance, err := wasmtime.NewInstance(store, module, []*wasmtime.Extern{})
    check(err)
    gcd := instance.GetExport("gcd").Func()
    val, err := gcd.Call(6, 27)
    fmt.Printf("gcd(6, 27) = %dn", val.(int32))
    check(err)
}
func check(e error) {
    if e != nil {
        panic(e)
    }
}

运行main.go 有如下输出:

$ go run main.go
gcd(6, 27) = 3

结语

其实wasm对于go的支持并不是特别好。在以后的文章中,我们使用rust语言创建一个wasm程序,然后直接使用诸如 wasmtime example.wasm 执行。

有疑问加站长微信联系

iiUfA3j.png!mobile

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK