使用GO编译wasm文件并在nodejs中使用

这篇具有很好参考价值的文章主要介绍了使用GO编译wasm文件并在nodejs中使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

使用GO编译wasm文件并在nodejs中使用

安装Go相关环境

# 安装GO
# mac使用homebrew安装
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install go

# vi ~/.bashrc, 添加如下内容
export GOPATH=$HOME/go
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin

# 确认安装成功
source ~/.bashrc
go version

// 取消联网下载库
export GO111MODULE=off 


# 安装tinygo
brew tap tinygo-org/tools
brew install tinygo

获取wasm_exec.js

wasm_exec.js是Go WebAssembly相关的JavaScript文件,用于加载和初始化WebAssembly运行时环境,创建一个全局的GO对象,已经JavaScript和WebAssembly之间进行通讯

该文件在GO和TinyGO中使用的略有不同, 使用不同方式打的包需要使用对应的wasm_exec.js文件,安装对应的包后可以以下位置找到它们,将其复制到项目目录下 

GO:
	$(go env GOROOT)/misc/wasm/wasm_exec.js
	
TinyGo:
	$(tinygo env TINYGOROOT)/targets/wasm_exec.js

斐波那契数计算的n种方法

1. 原生JS直接计算

// 执行方式: node fibonacci.js

// 原生JS环境运行
async function calcByJS(calcNum) {
  console.log('-----------原生JS运行环境-----------');

  console.time("原生JS耗时");
  const resultJS = calcFibonacci(calcNum);
  // console.log('原生JS计算结果:', resultJS);
  console.timeEnd("原生JS耗时");
  console.log('-----------原生JS运行环境-----------\n');

}
// JS计算斐波那契函数
function calcFibonacci(n) {
  if (n == 0) {
    return 0;
  } else if (n == 1) {
    return 1;
  } else {
    return calcFibonacci(n - 1) + calcFibonacci(n - 2);
  }
}

async function main() {
  const calcNum = 40
  await calcByPureGo(calcNum)
}

main()

// 执行效率: 计算fibonacci(40)耗时: 约1350ms

2. 原生GO直接计算

// 运行方式: go run fibonacci.go
package main

import (
	"fmt"
	"time"
)

func fibonacci(n uint) uint {
	if n == 0 {
		return 0
	} else if n == 1 {
		return 1
	} else {
		return fibonacci(n-1) + fibonacci(n-2)
	}
}

func main() {
	start := time.Now()
	n := uint(40)
	fibonacci(n)
	fmt.Println("纯GO运算时间:", time.Since(start).Milliseconds(),"ms")
}

// 执行效率: 计算fibonacci(40)耗时: 约470ms

3. GO打包成WASM包由JS进行调用

  • GO文件
package main

import (
	"syscall/js"
	"fmt"
	// "time"
)

//export fibonacci
func fibonacci(this js.Value, args []js.Value) interface{} {
	n := args[0].Int()

	result := calculateFibonacci(n)

	return js.ValueOf(result)
}

func calculateFibonacci(n int) int {
	if n <= 1 {
		return n
	}

	return calculateFibonacci(n-1) + calculateFibonacci(n-2)
}

func main() {
	// 注册fibonacci方法
	js.Global().Set("fibonacci", js.FuncOf(fibonacci))

	// 调用fibonacci方法
	// start := time.Now()
	// n := int(40)
	// fibonacci(js.Undefined(), []js.Value{js.ValueOf(n)})
	// fmt.Printf("纯GO耗时:%vms \n", time.Since(start).Milliseconds())
	fmt.Println("fibonacci方法注册成功")

	// 阻塞住 goroutine
	done := make(chan struct{}, 0)
	<-done
}

  • 打包命令: GOOS=js GOARCH=wasm go build -o ./fibonacci.wasm fibonacci.go

  • 调用was_exec.js文件完成WebAssembly运行时环境初始化

    // Copyright 2021 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.
    
    "use strict";
    
    globalThis.require = require;
    globalThis.fs = require("fs");
    globalThis.TextEncoder = require("util").TextEncoder;
    globalThis.TextDecoder = require("util").TextDecoder;
    
    globalThis.performance = {
      now() {
        const [sec, nsec] = process.hrtime();
        return sec * 1000 + nsec / 1000000;
      },
    };
    
    const crypto = require("crypto");
    const path = require("path")
    globalThis.crypto = {
      getRandomValues(b) {
        crypto.randomFillSync(b);
      },
    };
    
    
    require("./wasm_exec");
    
    // 加载Go编写的wasm文件
    async function getWasmOfGo(wasmPath) {
      const go = new Go();
      go.argv = [wasmPath];
      go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
      go.exit = process.exit;
      const { instance } = await WebAssembly.instantiate(fs.readFileSync(path.join(__dirname, wasmPath)), go.importObject);
    
      // 执行 Go WebAssembly 实例
      go.run(instance)
    }
    
    module.exports = getWasmOfGo
    
  • JS调用wasm文件执行

    // node fibonacci.js
    
    const getWasmOfGo = require('./go_init')
    
    // GO计算斐波那契函数
    async function calcByGo(num) {
      console.log('-----------Go打包成wasm包运行-----------');
      const wasmPath = 'fibonacci.wasm';
      console.time('GO-wasm总耗时')
    
      console.time('wasm初始化总耗时')
      await getWasmOfGo(wasmPath);
      console.timeEnd('wasm初始化总耗时')
    
      // 调用导出的函数并传递参数
      console.time('GO-wasm计算耗时')
      const result = fibonacci(num);
      // console.log('GO计算结果1', result);
      console.timeEnd('GO-wasm计算耗时');
    
      console.timeEnd('GO-wasm总耗时')
      console.log('-----------Go打包成wasm包运行-----------\n');
    }
    calcByGo(40)
    
    // module.exports = calcByGo
    
    -----------Go打包成wasm包运行-----------
    fibonacci方法注册成功
    wasm初始化总耗时: 436.300ms
    GO-wasm计算耗时: 2341.956ms
    GO-wasm总耗时: 2778.486ms
    -----------Go打包成wasm包运行-----------
    
    

4. TinyGo打包成wasm包运行

  • Go文件

    // tinygo_fibonacci.go
    
    package main
    
    import "syscall/js"
    
    func main() {
    	// 包装导出的函数作为闭包,并传递给js.FuncOf
    	fibFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
    		n := args[0].Int()
    		result := fibonacci(n)
    		return result
    	})
    
    	// 将包装后的函数赋值给全局对象的某个属性(例如window)
    	js.Global().Set("fibonacci", fibFunc)
    
    	select {}
    }
    
    // Fibonacci 函数
    func fibonacci(n int) int {
    	if n <= 1 {
    		return n
    	}
    	return fibonacci(n-1) + fibonacci(n-2)
    }
    
  • 打包命令 tinygo build -o tinygo_fibonacci.wasm -target wasm tinygo_fibonacci.go

  • 调用was_exec.js文件完成WebAssembly运行时环境初始化

    // Copyright 2021 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.
    
    "use strict";
    
    globalThis.require = require;
    globalThis.fs = require("fs");
    globalThis.TextEncoder = require("util").TextEncoder;
    globalThis.TextDecoder = require("util").TextDecoder;
    
    globalThis.performance = {
      now() {
        const [sec, nsec] = process.hrtime();
        return sec * 1000 + nsec / 1000000;
      },
    };
    
    const crypto = require("crypto");
    const path = require("path")
    globalThis.crypto = {
      getRandomValues(b) {
        crypto.randomFillSync(b);
      },
    };
    
    
    require("./wasm_exec_tiny");
    
    // 加载Go编写的wasm文件
    async function getWasmOfGo(wasmPath) {
      const go = new Go();
      go.argv = [wasmPath];
      go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
      go.exit = process.exit;
      const { instance } = await WebAssembly.instantiate(fs.readFileSync(path.join(__dirname, wasmPath)), go.importObject);
    
      // 执行 Go WebAssembly 实例
      go.run(instance)
    
    }
    
    module.exports = getWasmOfGo
    
  • JS文件

    const getWasmOfGo = require('./tinygo_init')
    
    // GO计算斐波那契函数
    async function calcByTinyGo(num) {
      const wasmPath = 'tinygo_fibonacci.wasm';
      console.log('-----------TinyGo打包成wasm包运行-----------');
    
      console.time('GO总耗时')
    
      console.time('wasm初始化总耗时')
      await getWasmOfGo(wasmPath);
      console.timeEnd('wasm初始化总耗时')
    
      // 调用导出的函数并传递参数
      console.time('GO计算耗时')
      const result = fibonacci(num);
      // console.log('GO计算结果', result);
      console.timeEnd('GO计算耗时');
    
      console.timeEnd('GO总耗时')
      console.log('-----------TinyGo打包成wasm包运行-----------');
    }
    
    module.exports = calcByTinyGo
    
    -----------TinyGo打包成wasm包运行-----------
    wasm初始化总耗时: 19.252ms
    GO计算耗时: 633.676ms
    GO总耗时: 653.138ms
    -----------TinyGo打包成wasm包运行-----------
    

    5. html调用GO打的wasm包

    需启动http服务打开才能调用, 可使用vscode 的LiveServer插件文章来源地址https://www.toymoban.com/news/detail-648240.html

    <!DOCTYPE html>
    <html>
    
    <head>
      <meta charset="utf-8">
      <title>TinyGo WebAssembly Demo</title>
      <script src="wasm_exec.js"></script>
      <!-- <script src="wasm_exec_tiny.js"></script> -->
    
      <script src="//aeu.alicdn.com/waf/interfaceacting220819.js"></script>
      <script src="//aeu.alicdn.com/waf/antidomxss_v640.js"></script>
      <script>
        const go = new Go();
    
        WebAssembly.instantiateStreaming(fetch('fibonacci.wasm'), go.importObject)
          .then(result => {
            go.run(result.instance);
          })
          .catch(err => {
            console.error(err);
          });
    
        // 在页面上定义fibonacci函数,并调用WebAssembly模块中的fibonacci函数
        function fibonacci(n) {
          const wasmFibonacci = window.fibonacci;
          if (wasmFibonacci === undefined || typeof wasmFibonacci !== 'function') {
            console.error('fibonacci function not found');
            return;
          }
          return wasmFibonacci(n);
        }
    
        async function test() {
          console.time('Web计算耗时');
          const result = await fibonacci(40)
          console.log(result); console.timeEnd('Web计算耗时');
        }
    
        // JS计算斐波那契函数
        async function calcByJS(calcNum) {
          console.time("原生JS耗时");
          const resultJS = calcFibonacci(calcNum);
          // console.log('原生JS计算结果:', resultJS);
          console.timeEnd("原生JS耗时");
        }
    
        function calcFibonacci(n) {
          if (n == 0) {
            return 0;
          } else if (n == 1) {
            return 1;
          } else {
            return calcFibonacci(n - 1) + calcFibonacci(n - 2);
          }
        }
      </script>
    </head>
    
    <body>
      <h1>TinyGo WebAssembly Demo</h1>
      <button onclick="test()">Calculate Fibonacci</button>
      <button onclick="calcByJS(40)">Calculate Fibonacci By JS</button>
    </body>
    
    </html>
    
    GO的wasm:Web计算耗时: 3429.2451171875 ms
    TinyGO的wasm: Web计算耗时: 963.423095703125 ms
    浏览器JS耗时: 原生JS耗时: 1429.368896484375 ms
    

到了这里,关于使用GO编译wasm文件并在nodejs中使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【go-zero】go-zero阿里云oss 前端上传文件到go-zero API服务 并在k8s pod中创建文件 并推送到阿里云oss 最佳实践

    问题:在本地通过上传文件,然后将文件推送到aliyun的oss中,是没问题的 但是部署到了k8s中,则出现了问题,一直报错没有创建的权限 思路:开始认为应该将该文件挂载到configmap中,然后通过这种方式修改了deployment和dockerfile。最终发现应该是go的创建文件路径方式搞错了,

    2024年02月13日
    浏览(48)
  • go~wasm插件的开发

    Go和TinyGo是两种不同的Go语言编译器,它们之间有以下几点区别: 目标平台 : Go:Go语言编译器主要面向通用计算机平台,如Windows、Linux、macOS等。 TinyGo:TinyGo专注于支持嵌入式系统和物联网设备等资源受限的平台,如微控制器、嵌入式设备、WebAssembly等。 性能 : Go:Go编译

    2024年04月08日
    浏览(32)
  • Golang - go build打包文件

    Go编译打包文件 1、简单打包 程序 main1.go: 打包: # 在linux服务上执行下面的3个命令 执行: 2、打包时为程序中的变量设置值 程序 main2.go : 打包:打包方式和上面一样,这里只介绍linux下的打包。 # 在linux服务上执行下面的命令 执行: 3、打包时指定名称 执行: go build的时

    2024年02月09日
    浏览(43)
  • go~istio加载wasm的步骤

    https://github.com/higress-group/proxy-wasm-go-sdk/tree/main/proxywasm https://github.com/tetratelabs/proxy-wasm-go-sdk https://github.com/alibaba/higress/blob/main/plugins/wasm-go/pkg/wrapper https://tinygo.org/docs/reference/ https://tinygo.org/docs/reference/lang-support/stdlib/ TinyGo 是一个 Go 编译器,旨在用于微控制器,WebAssembly(WASM)

    2024年04月08日
    浏览(90)
  • Linux下安装nodeJS,并在jenkins下配置

    jenkins服务器下安装nodejs报错: 安装的nodejs版本: linux系统版本: 经查找是版本不匹配,可通过降低nodejs的版本避免报错。 1)进入Linux服务器的目录,执行下载,命令为 2)压缩包解压,命令 3)重命名刚解压的文件夹为nodejs 耐心等待安装,出现提示输入y即可; 4)打开环境

    2024年02月02日
    浏览(45)
  • 使用Blazor WASM实现可取消的多文件带校验并发分片上传

    上传大文件时,原始HTTP文件上传功能可能会影响使用体验,此时使用分片上传功能可以有效避免原始上传的弊端。由于分片上传不是HTTP标准的一部分,所以只能自行开发相互配合的服务端和客户端。文件分片上传在许多情况时都拥有很多好处,除非已知需要上传的文件一定

    2024年02月08日
    浏览(34)
  • golang gRPC:根据.protobuf文件生成go代码

    安装 protoc 编译器。如果没有安装,可以参考官方文档进行安装。 使用 protoc 命令生成 gRPC 代码: 此命令将生成 .pb.go 和 _grpc.pb.go 文件,其中包含 protobuf 和 gRPC 的代码实现. –go_out选项会生成纯粹的Protocol Buffer消息代码,这包括Go语言的消息结构体和一些辅助方法。如果你只

    2024年02月14日
    浏览(44)
  • 【Golang】解决Go test执行单个测试文件提示未定义问题

    目录 背景 根本原因 解决方法 解决 多级引用或多个引用包的情况 总结  资料获取方法 很多人记录过怎么执行Go test单个文件或者单个函数,但是要么对执行单文件用例存在函数或变量引用的场景避而不谈,要么提示调用了其它文件中的模块会报错。其实了解了go test命令的机

    2024年02月14日
    浏览(40)
  • Go Build编译打包文件

    程序 main1.go : 打包: 执行: 程序 main2.go : 打包:打包方式和上面一样,这里只介绍linux下的打包。 执行: go build的时候还有别的其它参数,如果有需要请查询相关文档。

    2024年01月18日
    浏览(35)
  • 【Golang中的Go Module使用】

    Golang中的Go Module是一个用于包管理和版本控制的工具。在本文中,我们将深入探讨Go Module的相关知识,包括其定义、使用方法以及一些常见的应用场景。 Go Module是Golang中的包管理和版本控制工具,它的发展历程、用法、意义以及相关指令都对于Golang开发者来说非常重要。在本

    2024年02月16日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包