共计 3121 个字符,预计需要花费 8 分钟才能阅读完成。
Golang 在 1.11 版本中开始反对 WebAssembly。
基本上目前有两种应用场景:
浏览器端
— 将 golang 编写的程序编译成 wasm,而后在浏览器中应用编译好的 wasm。这样的意义在于,给了咱们应用 golang 编写前端利用的能力,并且能够享受 golang 自身具备的诸如类型平安和协程的 future。服务端
— golang 程序中应用其余语言编写的 wasm 模块。
截止到目前,golang 并不能反对 wasi,不过正在布局中。具体能够查阅 issue。
上面咱们通过两个 demo 别离演示一下这两种场景的应用姿态。
浏览器端
1:首先咱们创立一个 go 工程hello-go
,用来生成 wasm 模块。代码比较简单,如下:
package main
import ("fmt")
func main() {fmt.Println("Hello-go!")
}
而后咱们开始应用如下命令编译,会生成一个 lib.wasm
文件:
GOARCH=wasm GOOS=js go build -o lib.wasm main.go
2:创立一个 index.html 页面,该页面会应用到上一步编译好的lib.wasm
。
<!--
Copyright 2018 The Go Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
-->
<html>
<head>
<meta charset="utf-8" />
<title>Go wasm</title>
</head>
<body>
<script src="wasm_exec.js"></script>
<script>
if (!WebAssembly.instantiateStreaming) {
// polyfill
WebAssembly.instantiateStreaming = async (resp, importObject) => {const source = await (await resp).arrayBuffer();
return await WebAssembly.instantiate(source, importObject);
};
}
const go = new Go();
let mod, inst;
WebAssembly.instantiateStreaming(fetch("lib.wasm"), go.importObject).then(
result => {
mod = result.module;
inst = result.instance;
document.getElementById("runButton").disabled = false;
}
);
async function run() {await go.run(inst);
inst = await WebAssembly.instantiate(mod, go.importObject); // reset instance
}
</script>
<button onClick="run();" id="runButton" disabled>Run</button>
</body>
</html>
大家能够看到应用了 WebAssembly.instantiateStreaming
办法加载 wasm 文件到浏览器页面中。
咱们还须要从 misc/wasm
复制 wasm_exec.js
文件。
$ cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
3: 咱们须要有一个简略的基于 net/http
的文件服务器,以提供咱们的 index.html
和其余各种 WebAssembly 文件:
package main
import (
"flag"
"log"
"net/http"
)
var (listen = flag.String("listen", ":8080", "listen address")
dir = flag.String("dir", ".", "directory to serve")
)
func main() {flag.Parse()
log.Printf("listening on %q...", *listen)
log.Fatal(http.ListenAndServe(*listen, http.FileServer(http.Dir(*dir))))
}
启动该服务器后,当您导航至 localhost:8080
时,应该看到“run”按钮是可单击的,并且如果您在浏览器中关上控制台,则应该看到,每次单击该按钮,它都会打印出Hello-go!
。
本示例比较简单,实际上在 go 代码中能够操作 dom,实现性能更加丰盛的 wasm 模块。
服务端
在 go 代码中应用 wasm,须要用到 wasmer-go — 基于 Wasmer 的 Go 的残缺且成熟的 WebAssembly 运行时。
该运行时性能十分强悍,具体性能测试数据如下:
要援用的 wasm 模块,为了不便,大家能够间接下载 [simple.wasm](https://link.zhihu.com/?target=https%3A//github.com/wasmerio/wasmer-go/blob/master/wasmer/test/testdata/examples/simple.wasm)
。该模块由 rust 语言编写,实现一个简略的两数求和的性能,具体代码逻辑如下:
#[no_mangle]
pub extern fn sum(x: i32, y: i32) -> i32 {x + y}
接下来咱们编写咱们的 golang 程序,在程序中执行 simple.wasm
模块。
package main
import (
"fmt"
wasm "github.com/wasmerio/go-ext-wasm/wasmer"
)
func main() {
// Reads the WebAssembly module as bytes.
bytes, _ := wasm.ReadBytes("simple.wasm")
// Instantiates the WebAssembly module.
instance, _ := wasm.NewInstance(bytes)
defer instance.Close()
// Gets the `sum` exported function from the WebAssembly instance.
sum := instance.Exports["sum"]
// Calls that exported function with Go standard values. The WebAssembly
// types are inferred and values are casted automatically.
result, _ := sum(5, 37)
fmt.Println(result) // 42!
}
运行咱们的代码:
$ go run main.go
go: finding module for package github.com/wasmerio/go-ext-wasm/wasmer
go: found github.com/wasmerio/go-ext-wasm/wasmer in github.com/wasmerio/go-ext-wasm v0.3.1
# command-line-arguments
clang: warning: argument unused during compilation: '-nopie' [-Wunused-command-line-argument]
42
总结
本文 WebAssembly 和 go 两种应用场景,并通过两个简略的 demo,试图让大家了解这两种场景和应用办法。