2024年Go 生态最火的3个 WebAssembly 运行时

家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!

前言

本文主要和大家介绍2023年Go 生态最火的3个 WebAssembly 运行时!在年初,我也确实使用 WebAssembly 将客户端应用成功移植到了 Web,这也是为什么我一直对 WebAssembly 充满好奇的原因。我甚至在头条上开了一个合集《WebAssembly 前沿技术》来专门探讨 WebAssembly ,并将持续关注 WebAssembly 的最新动态。

下面是已发布部分文章传送门:

正如大家所看到的,当我们还在迟疑是否要在日常开发中引入 WebAssembly 的时候,很多优秀的应用、工具已经开始吃 WebAssembly 的红利了,而且取得了不错的成就,这可能也是为什么各个浏览器厂商、开发者如此热衷 WebAssembly 的原因吧。

前几天已经重点介绍过与 JavaScript 生态相关的《全网最火的 5+优秀 WebAssembly 运行时》,今天带着大家细数那些在 Go 语言中优秀的 WebAssembly 运行时,希望大家在使用 Go开发的时候能真正用得上。话不多说,直接开始!

1.wasmer-go

1.1 什么是 wasmer-go

基于 Wasmer 的完整、成熟的 Go WebAssembly 运行时。主要特征如下:

  • 易于使用:wasmer API 模仿标准的 WebAssembly API
  • 快速:wasmer 尽可能快地执行 WebAssembly 模块,接近本机速度
  • 安全:所有对 WebAssembly 的调用都将很快,但更重要的是,完全安全且在沙盒中。

wasmer-go 嵌入了编译为共享库对象的 Wasmer 运行时,因此可使用 CGO 来使用它。同时提供了一组预编译的共享库对象。因此,该库可在以下平台上运行(并经过测试):

1.2 使用 wasmer-go

可以通过如下命令快速安装 wasmer-go:

$ go get github.com/wasmerio/wasmer-go/wasmer

安装后即可在代码中引入 WebAssembly 模块:

// 这里是Go语言程序
package main
import (
	"fmt"
	"io/ioutil"
	wasmer "github.com/wasmerio/wasmer-go/wasmer"
)
func main() {
    wasmBytes, _ := ioutil.ReadFile("simple.wasm")
    // simple.wasm表示已编译的 WebAssembly 二进制文件
    engine := wasmer.NewEngine()
    store := wasmer.NewStore(engine)
    // 编译模块
    module, _ := wasmer.NewModule(store, wasmBytes)
    //实例化模块
    importObject := wasmer.NewImportObject()
    instance, _ := wasmer.NewInstance(module, importObject)
    // 从 WebAssembly 实例获取“sum”导出函数。
    sum, _ := instance.Exports.GetFunction("sum")
    // 使用 Go 标准值调用导出函数。
    // 推断 WebAssembly 类型并自动转换值。
    result, _ := sum(5, 37)
    fmt.Println(result)
    // 输出 42!
}

然后执行如下命令即可:

go run simple.go

目前 wasmer-go 在 Github 上 2.4k 的 star、150+的 fork、超过 60+的项目使用它。

关于Wasmer的更多介绍可阅读我的另外一篇文章,即《全网最火的 5+优秀 WebAssembly 运行时》,参考资料已经在文末。

CGO: 是一个Go 语言自带的特殊工具,可以使用命令go tool cgo 来运行。 cgo可以用于生成能够调用C 语言代码的Go语言源文件,也就是说所有启用了CGO 特性的Go 代码,都会首先经过cgo 的预处理。

2.wazero

2.1 wazero

wazero 是用 Go 编写的符合 WebAssembly 核心规范 1.0 和 2.0 的运行时。 它具有零依赖性,并且不依赖于 CGO, 这意味着可以运行其他语言的应用程序并仍然保持交叉编译。导入 wazero 并使用以任何语言编写的代码扩展 Go 应用程序!

wazero 支持两种运行时配置,编译器已集成。 默认情况下,例如: wazero.NewRuntime(ctx)如果支持,则使用编译器,开发者也可以如下方式强制使用解释器:

r := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfigInterpreter())

wazero 运行时只要包括以下两个组成部分:

  • 解释器 Interpreter: 是 Wasm 虚拟机的一个简单的基于解释器的实现。 它的实现没有任何平台(GOARCH、GOOS)特定代码,因此解释器可用于 Go 可用的任何编译目标(例如: riscv64)。
  • 编译器 Compiler:在 Runtime.CompileModule 期间提前将 WebAssembly 模块编译成机器代码 (AOT), 这意味着 WebAssembly 函数在运行时本机执行。 编译器比解释器快,通常快一个数量级 (10x) 或更多, 其是在没有主机特定依赖性的情况下完成的。

2.2 wazero 使用

下面示例显示如何使用 WebAssembly 中定义的加法函数扩展 Go 应用程序。

$ go run add.go 7 9
7 + 9 = 16

wazero 是一个 WebAssembly 运行时,嵌入在主机应用程序中。 要运行 WebAssembly 函数,需要访问 WebAssembly 二进制文件 (Wasm),通常是一个 %.wasm 文件。

add.wasm 是使用 TinyGo 从 add.go 编译而来的,因为它是将 Go 源代码编译为 Wasm 的最常用方法,这是构建 %.wasm 二进制文件的最小命令。

cd testdata; tinygo build -o add.wasm -target=wasi add.go

目前 wazero 在 Github 上 2.7k 的 star、150+的 fork、超过 230+的项目使用它,代码贡献者超过 35+。

3.wasmtime-go

3.1 什么是 wasmtime-go

Go 生态的 Wasmtime 字节码联盟项目,wasmtime-go 使用 CGO 来使用用 Rust 编写的 Wasmtime 项目的 C API。 Wasmtime 的预编译二进制文件在标记版本上签入此存储库,因此开发者不必在本地安装 Wasmtime。

wasmtime-go 项目目前仅适用于 Linux x86*64、macOS x86_64 和 Windows x86_64。 在其他平台上构建将需要预先构建 Wasmtime 并使用 CGO** env vars 才能正确编译。wasmtime-go 项目已经通过 Go 1.13 或更高版本测试。

可以通过如下命令快速安装:

go get -u github.com/bytecodealliance/wasmtime-go/v7@v7.0.0

如果是 bazel 用户,需要将以下内容添加到 WORKSPACE 文件中:

go_repository(
  (name = 'com_github_bytecodealliance_wasmtime_go'),
  (importpath = 'github.com/bytecodealliance/wasmtime-go/v7'),
  (version = 'v7.0.0')
);

3.2 使用 wasmtime-go

下面是使用 wasmtime-go 的 hello world 示例:

package main
import (
    "fmt"
    "github.com/bytecodealliance/wasmtime-go/v7"
)
func main() {
    // wasmtime 中的几乎所有操作都需要一个上下文的“store”参数来共享,所以首先创建它
    store := wasmtime.NewStore(wasmtime.NewEngine())
    // 编译模块需要 WebAssembly 二进制输入
    // 但是 wasmtime 包也支持将 WebAssembly 文本格式转换为二进制格式。
    wasm, err := wasmtime.Wat2Wasm(`
      (module
        (import "" "hello" (func $hello))
        (func (export "run")
          (call $hello))
      )
    `)
    check(err)
    // 一旦有了二进制“wasm”,就可以将其编译成一个“*Module”
    // 它代表已编译的 JIT 代码。
    module, err := wasmtime.NewModule(store.Engine, wasm)
    check(err)
    //  `hello.wat` 文件导入了一项,所以在这里创建该函数
    item := wasmtime.WrapFunc(store, func() {
        fmt.Println("Hello from Go!")
    })
    //接下来实例化一个模块,这是链接所有导入的地方。
    // 有一个导入,所以需要在这里传递它。
    instance, err := wasmtime.NewInstance(store, module, []wasmtime.AsExtern{item})
    check(err)
    // 在实例化之后,可以查找 run 函数并调用它
    run := instance.GetFunc(store, "run")
    if run == nil {
        panic("not a function")
    }
    _, err = run.Call(store)
    check(err)
}
func check(e error) {
    if e != nil {
        panic(e)
    }
}

目前 wasmtime-go 在 Github 上 590+ 的 star、60+的 fork。

4.本文总结

本文主要和大家介绍Go 生态最火的3个 WebAssembly 运行时!因为篇幅有限,文章并没有过多展开,如果有兴趣,可以在我的主页继续阅读,同时文末的参考资料提供了大量优秀文档以供学习。最后,欢迎大家点赞、评论、转发、收藏!

参考资料

https://www.toutiao.com/article/7208714402630058531/

https://github.com/wasmerio/wasmer-go

https://github.com/tetratelabs/wazero/tree/main/examples/basic

https://github.com/tetratelabs/wazero

https://github.com/bytecodealliance/wasmtime-go

封面图文章参考地址:https://dev.to/taherfattahi/build-a-chat-service-using-golang-and-webassembly-part-1-1pee

封面图作者:Taher Fattahi的《Build a Chat service using GoLang and WebAssembly (part 1)》

原文链接:,转发请注明来源!