Golang 在 1.11 版本中开始反对WebAssembly。

基本上目前有两种应用场景:

  • 浏览器端 -- 将golang 编写的程序编译成wasm,而后在浏览器中应用编译好的wasm。这样的意义在于,给了咱们应用golang编写前端利用的能力,并且能够享受golang自身具备的诸如类型平安和协程的future。
  • 服务端 -- golang程序中应用其余语言编写的wasm模块。
截止到目前,golang并不能反对wasi,不过正在布局中。具体能够查阅 issue 。

上面咱们通过两个demo别离演示一下这两种场景的应用姿态。

浏览器端

1:首先咱们创立一个go工程hello-go,用来生成wasm模块。代码比较简单,如下:

package mainimport (    "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-stylelicense 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 mainimport (    "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 mainimport (    "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/wasmergo: found github.com/wasmerio/go-ext-wasm/wasmer in github.com/wasmerio/go-ext-wasm v0.3.1# command-line-argumentsclang: warning: argument unused during compilation: '-nopie' [-Wunused-command-line-argument]42

总结

本文WebAssembly和go两种应用场景,并通过两个简略的demo,试图让大家了解这两种场景和应用办法。