Golang编写WebAssembly程序
CSDN首席喷子
2026年07月10日 19:14

WebNN是一个非常好用的推理工具,但如果遇到一些非端到端的模型,依然还是需要自行编写算法。原生Javascript的类型系统过于逆天,根本没法跑一些科学程序。好在我们有号称互联网C语言的Golang,它甚至原生支持WebAssembly。

现在以一个计算交并比的函数为例:

代码块
Go
自动换行
复制代码
package main

import (
	"syscall/js"
)

func Area(box []float32) float32 {
	w := box[2] - box[0]
	h := box[3] - box[1]
	return w * h
}

func MaxFloat32(a float32, b float32) float32 {
	if a > b {
		return a
	} else {
		return b
	}
}

func MinFloat32(a float32, b float32) float32 {
	if a > b {
		return b
	} else {
		return a
	}
}

func Intersection(box1 []float32, box2 []float32) []float32 {
	x1 := MaxFloat32(box1[0], box2[0])
	y1 := MaxFloat32(box1[1], box2[1])
	x2 := MinFloat32(box1[2], box2[2])
	y2 := MinFloat32(box1[3], box2[3])

	if x2 < x1 || y2 < y1 {
		return []float32{0, 0, 0, 0}
	}

	return []float32{x1, y1, x2, y2}
}

func Union(box1 []float32, box2 []float32) float32 {
	return Area(box1) + Area(box2) - Area(Intersection(box1, box2))
}

func IoU(box1 []float32, box2 []float32) float32 {
	inter := Area(Intersection(box1, box2))
	union := Union(box1, box2)
	if union == 0 {
		return 0
	}
	return inter / (union + 1e-6)
}

func GIoU(box1 []float32, box2 []float32) float32 {
	iou := IoU(box1, box2)
	union := Union(box1, box2)

	cx1 := MinFloat32(box1[0], box2[0])
	cy1 := MinFloat32(box1[1], box2[1])
	cx2 := MaxFloat32(box1[2], box2[2])
	cy2 := MaxFloat32(box1[3], box2[3])
	cArea := MaxFloat32((cx2-cx1), 0.0) * MaxFloat32((cy2-cy1), 0.0)

	giou := iou - (cArea-union)/(cArea+1e-6)
	return giou
}

// Wrapper function for javascript.
func Calculate_IoU(this js.Value, args []js.Value) any {
	box1 := []float32{float32(args[0].Index(0).Float()), float32(args[0].Index(1).Float()), float32(args[0].Index(2).Float()), float32(args[0].Index(3).Float())}
	box2 := []float32{float32(args[1].Index(0).Float()), float32(args[1].Index(1).Float()), float32(args[1].Index(2).Float()), float32(args[1].Index(3).Float())}
	iou := IoU(box1, box2)
	return js.ValueOf(iou)
}

// Wrapper function for javascript.
func Calculate_GIoU(this js.Value, args []js.Value) any {
	box1 := []float32{float32(args[0].Index(0).Float()), float32(args[0].Index(1).Float()), float32(args[0].Index(2).Float()), float32(args[0].Index(3).Float())}
	box2 := []float32{float32(args[1].Index(0).Float()), float32(args[1].Index(1).Float()), float32(args[1].Index(2).Float()), float32(args[1].Index(3).Float())}
	giou := GIoU(box1, box2)
	return js.ValueOf(giou)
}

func main() {
	// a, b := []float32{10, 10, 50, 50}, []float32{30, 30, 70, 70}
	// iou := IoU(a, b)
	// giou := GIoU(a, b)
	// fmt.Printf("IoU is %.5f, GIoU is %.5f", iou, giou)

	done := make(chan int, 0)
	js.Global().Set("calculate_iou", js.FuncOf(Calculate_IoU))
	js.Global().Set("calculate_giou", js.FuncOf(Calculate_GIoU))
	<-done
}
复制成功

配置如下:

代码块
PlainText
自动换行
复制代码
GOARCH=wasm
GOOS=js
CGO_ENABLED=1
复制成功

前端调用代码如下(wasm_exec.js在GOROOT/misc/wasm文件夹):

代码块
JavaScript
自动换行
复制代码
<!DOCTYPE html>
<html>
	<head>
		<title>Golang Web Assembly</title>
		<script src="./wasm_exec.js"></script>
	</head>
	<body>
		<script>
			function main() {
				var a = new Float32Array([10, 10, 50, 50]);
				var b = new Float32Array([30, 30, 70, 70]);
				var iou = calculate_iou(a, b);
				var giou = calculate_giou(a, b);
				console.log(`IoU:${iou}, GIoU:${giou}`);
			}
		
			window.onload = function() {
				const go = new Go();
				WebAssembly.instantiateStreaming(fetch('./main.wasm'), go.importObject).then((result)=> {
					go.run(result.instance);
					main();
				});
			}
		</script>
	</body>
</html>
复制成功