misc/wasm: Go's WASM running slow in Node v19

aiazj4mn  于 2个月前  发布在  Go
关注(0)|答案(3)|浏览(28)

你正在使用哪个版本的Go( go version )?

$ go version
go version go1.20.3 darwin/amd64

这个问题在最新版本中是否会重现?

是的

你正在使用什么操作系统和处理器架构( go env )?

go env 输出

$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/penghaoh/.cache/go-build"
GOENV="/Users/penghaoh/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/penghaoh/Workplace/my_go_workspace/pkg/mod"
GONOPROXY="*"
GONOSUMDB="*"
GOOS="darwin"
GOPATH="/Users/penghaoh/Workplace/my_go_workspace"
GOPRIVATE="*"
GOPROXY="direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.20.3"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/h0/6tx4n9fn59z1vj88py9mncmr00vbmk/T/go-build2636679718=/tmp/go-build -gno-record-gcc-switches -fno-common"

你做了什么?

  • 尝试用Go编写一个项目,重用一些逻辑

main.go

var done chan bool

func init() {
	done = make(chan bool)
}

func main() {
	var hash js.Func
	hash = js.FuncOf(func(this js.Value, args []js.Value) any {
		h := crypto.SHA512.New()
		h.Write([]byte(args[0].String()))
		return hex.EncodeToString(h.Sum(nil))
	})
	js.Global().Set("wasmHash", hash)
	var close js.Func
	close = js.FuncOf(func(this js.Value, args []js.Value) any {
		defer close.Release()
		defer hash.Release()
		done <- true
		return nil
	})
	js.Global().Set("close", close)
	<-done
}
  • GOOS=js GOARCH=wasm go build -o wasm.wasm main.go 构建它,二进制文件大小为19.4 MB(我添加了一些额外的依赖项来模拟这个原型的实际项目)
  • 压缩wasm文件 gzip -9 -v -c wasm.wasm > wasm.wasm.gz
  • node ./main.js 运行它

main.js

const pako = require("pako");
require("./wasm_exec");
fs = require("fs");

const wasmBuffer = new Uint8Array(pako.ungzip(fs.readFileSync("wasm.wasm.gz")));
const go = new Go();
go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
go.exit = process.exit;
WebAssembly.instantiate(wasmBuffer, go.importObject).then((wasmModule) => {
go.run(wasmModule.instance);
console.log(wasmHash("asdf"));
close();
process.on("exit", (code) => {
// Node.js exits if no event handler is pending

// commend the block avoid deadlock
if (code === 0 && !go.exited) {
  // deadlock, make Go print error and stack traces
  go._pendingEvent = { id: 0 };
  go._resume();
}
process.exit();

});
return;
});

你期望看到什么?

显示 asdf 的哈希结果。

你看到了什么?

如果二进制文件很大,在我看到结果后,我的机器上需要5秒钟才能退出。然而,令我惊讶的是,如果我用deno重写js文件,它在打印结果后立即退出。
deno.js

import * as _ from "./wasm_exec.js";
const go = new window.Go();
const f = await Deno.open("./wasm.wasm");
const buf = await Deno.readAll(f);
const inst = await WebAssembly.instantiate(buf, go.importObject);
go.run(inst.instance);
const result = wasmHash("asdf");
console.log(result);

bbuxkriu

bbuxkriu1#

这听起来更像是Node.js比Deno慢的问题,但也许我们可以在这里做些什么?
cc @golang/wasm

f4t66c6m

f4t66c6m2#

我不觉得这是性能差异,因为使用Nodejs的实际结果显示得很快。在调用所有go func之后,只是出现了奇怪的挂起。即使我明确地调用process.exit(0),并且调用栈为空,它也无法正常工作。

rseugnpd

rseugnpd3#

这可能是Node.js中未修复的以下错误:nodejs/node#36616。如果你真的想解决这个问题,可以尝试一种可怕的方法来绕过它:nodejs/node#36616(评论)。

相关问题