原文在这里

由 Johan Brandhorst-Satzkorn, Julien Fabre, Damian Gryski, Evan Phoenix, and Achille Roussel 发布于 2023年9月13日

Go 1.21添加了一个新的端口,通过新的GOOS值wasip1来定位WASI预览1系统调用API。该端口建立在Go 1.11引入的现有WebAssembly端口的基础上。

WebAssembly 是什么

WebAssembly(Wasm)是一种最初设计用于Web的二进制指令格式。它代表了一个标准,允许开发人员在Web浏览器中以接近本机速度直接运行高性能、低级别的代码。

Go首次在1.11版本中添加了对编译成Wasm的支持,通过js/wasm端口实现。这允许使用Go编译器编译的Go代码在Web浏览器中执行,但需要一个JavaScript执行环境。

随着Wasm的使用增加,除了在浏览器之外的用例也增多。许多云提供商现在提供服务,允许用户直接执行Wasm可执行文件,利用新的WebAssembly系统接口(WASI)系统调用API。

WebAssembly 系统接口

WASI定义了一个用于Wasm可执行文件的系统调用API,允许它们与系统资源进行交互,如文件系统、系统时钟、随机数据工具等等。WASI规范的最新版本被称为wasi_snapshot_preview1,从中我们派生出了GOOS名称wasip1。新版本的API正在开发中,未来在Go编译器中支持它们可能意味着添加一个新的GOOS。

WASI的创建使得许多Wasm运行时(宿主)能够围绕其标准化它们的系统调用API。一些Wasm/WASI宿主的示例包括WasmtimeWazeroWasmEdgeWasmerNodeJS。还有许多云提供商提供Wasm/WASI可执行文件的托管服务。

Go 中如何使用 WebAssembly

请确保已安装至少1.21版本的Go。对于此演示,我们将使用Wasmtime主机来执行我们的二进制文件。让我们从一个简单的 main.go 开始:

package main

import "fmt"

func main() {
fmt.Println("Hello world!")
}

使用如下命令进行编译:

$ GOOS=wasip1 GOARCH=wasm go build -o main.wasm main.go

这将会生成一个名为 main.wasm 的文件,我们可以使用 wasmtime 执行:

$ wasmtime main.wasm
Hello world!

这就是开始使用Wasm/WASI所需的全部!几乎所有Go的功能都可以在 wasip1 上正常工作。要了解有关WASI如何与Go一起工作的详细信息,请参阅提案

测试 wasip1

构建和运行二进制文件很容易,但有时我们希望能够直接运行 go test,而无需手动构建和执行二进制文件。与 js/wasm 端口类似,Go安装中包含的标准库分发版本附带一个文件,使这个过程变得非常简单。在运行Go测试时,将 misc/wasm 目录添加到 PATH 中,它将使用你选择的Wasm主机来运行测试。这是通过 go test 在PATH中找到此文件时自动执行 misc/wasm/go_wasip1_wasm_exec 来实现的:

$ export PATH=$PATH:$(go env GOROOT)/misc/wasm
$ GOOS=wasip1 GOARCH=wasm go test ./...

这将使用 Wasmtime 运行 go test。可以使用环境变量 GOWASIRUNTIME 来控制所使用的Wasm主机。目前支持的变量值包括 wazerowasmedgewasmtimewasmer。请注意,Go wasip1 二进制文件在所有主机上尚不能完美执行(参见#59907#60097)。

也可以使用 go run来执行上面的程序:

$ GOOS=wasip1 GOARCH=wasm go run ./main.go
Hello world!

使用go:wasmimport在Go中包装Wasm函数

除了新的 wasip1/wasm 端口外,Go 1.21还引入了一个新的编译器指令:go:wasmimport。它指示编译器将对带有注释的函数的调用转换为对由主机模块名称和函数名称指定的函数的调用。这个新的编译器功能允许我们在Go中定义wasip1系统调用API,以支持新的端口,但它不限于在标准库中使用。

例如,wasip1系统调用API定义了 random_get 函数,并通过runtime包中定义的函数包装器暴露给Go标准库。它看起来像这样:

//go:wasmimport wasi_snapshot_preview1 random_get
//go:noescape
func random_get(buf unsafe.Pointer, bufLen size) errno

然后,将这个函数包装器包装在标准库中供使用的更人性化的函数中:

func getRandomData(r []byte) {
if random_get(unsafe.Pointer(&r[0]), size(len(r))) != 0 {
throw("random_get failed")
}
}

这样,用户可以使用字节切片调用 getRandomData ,并最终将其传递给主机定义的 random_get 函数。同样,用户可以为主机函数定义自己的包装器。

要了解如何在Go中包装Wasm函数的复杂性的更多细节,请参阅go:wasmimport提案

局限性

虽然wasip1端口通过了所有标准库测试,但Wasm架构有一些显着的基本限制,可能会让用户感到惊讶。

Wasm是一个没有并行性的单线程架构。调度器仍然可以调度goroutine以并发运行,标准输入/输出/错误是非阻塞的,因此一个goroutine可以在另一个读取或写入时执行,但是任何主机函数调用(例如使用上面的示例请求随机数据)都会导致所有goroutine阻塞,直到主机函数调用返回。

wasip1 API中一个显着缺失的功能是完整的网络套接字实现。wasip1只定义了对已经打开的套接字进行操作的函数,这使得无法支持Go标准库的一些最流行的功能,如HTTP服务器。像Wasmer和WasmEdge这样的主机实现了wasip1 API的扩展,允许打开网络套接字。尽管Go编译器没有实现这些扩展,但存在第三方库,github.com/stealthrocket/net,使用go:wasmimport允许在支持的Wasm主机上使用net.Dial和net.Listen。这允许在使用此包时创建net/http服务器和其他与网络相关的功能。

Go中的Wasm的未来

wasip1/wasm 端口的添加只是我们希望引入Go的Wasm功能的开端。请密切关注问题跟踪器,了解有关将Go函数导出到Wasm(go:wasmexport)、32位端口和未来WASI API兼容性的提案。

参与其中

如果你正在尝试并希望为Wasm和Go做出贡献,请参与其中!Go问题跟踪器跟踪所有正在进行的工作,Gophers Slack上的 #webassembly 频道是讨论Go和WebAssembly的好地方。我们期待听到你的声音!


声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。

Author: mengbin

blog: mengbin

Github: mengbin92

cnblogs: 恋水无意


WASI support in Go的更多相关文章

  1. Android注解使用之使用Support Annotations注解优化代码

    前言: 前面学习总结了Java注解的使用,博客地址详见Java学习之注解Annotation实现原理,从本质上了解到什么注解,以及注解怎么使用?不要看见使用注解就想到反射会影响性能之类,今天我们就来学 ...

  2. Android Support 包知识

    Android Support Library包是一组代码库, 它提供了向后版本的framework API的兼容, 这些代码库实现的效果和只能在指定版本中使用的API一样好. 每个Support L ...

  3. 解决Native atomics support not found问题

    今天用arm-none-linux-gnueabi交叉编译libmysqclient.so,出现Native atomics support not found问题 进入mysql-connector ...

  4. 使用 CoordinatorLayout 出错 inflating class android.support.design.widget.CoordinatorLayout

    ava.lang.RuntimeException: Unable to start activity ComponentInfo{com.czr.ianpu/com.czr.ianpu.MainAc ...

  5. Your app declares support for audio in the UIBackgroundModes key in your Info.plist 错误

    提交AppStore时候被拒绝 拒绝原因:Your app declares support for audio in the UIBackgroundModes key in your Info.p ...

  6. 在布局中使用android.support.v4.app.Fragment的注意事项

    1.Activity必须继承android.support.v4.app.FragmentActivity 2.fragment标签的name属性必须是完全限定包名,如下: <LinearLay ...

  7. 启动项目的时候报驱动错误: not support oracle driver 1.0

    问题:今天在使用pom导入oracle14的包时候发现怎么都下载不过来.网上查了一下发现是因为Oracle驱动需要官方授权,所以在pom.xml文件直接配置,无法下载成功. 解决方法就是下载oracl ...

  8. Android Support Library

    title: Android Support Library tags: Support Library,支持库 grammar_cjkRuby: true --- DATE: 2016-5-13. ...

  9. How To Install Proxmox Nested on VMware ESXi (Full Support OpenVZ & KVM)

    https://imanudin.net/2015/03/04/how-to-install-proxmox-nested-on-vmware-esxi-full-support-openvz-kvm ...

  10. CAST function should support INT synonym for SIGNED. i.e. CAST(y AS INT)

      Login / Register Developer Zone Bugs Home Report a bug Statistics Advanced search Saved searches T ...

随机推荐

  1. qq飞车端游最全按键指法教学

    目录 起步篇 超级起步 弹射起步 段位起步 基础篇 点飘 撞墙漂移 撞墙点喷 进阶篇 双喷 叠喷 断位漂移 段位双喷 侧身漂移 快速出弯 CW WCW CWW 牵引 甩尾点飘 甩尾漂移 右侧卡 左侧卡 ...

  2. 逍遥自在学C语言 | for循环详解

    前言 C语言中的循环结构时,for循环是最常用的一种.它允许重复执行一段代码,直到满足特定条件为止. 本文将详细介绍for循环的用法,并提供相关的可编译运行的C代码示例. 一.人物简介 第一位闪亮登场 ...

  3. 基于 prefetch 的 H5 离线包方案

    前言 对于电商APP来讲,使用H5技术开发的页面占比很高.由于H5加载速度非常依赖网络环境,所以为了提高用户体验,针对H5加载速度的优化非常重要.离线包是最常用的优化技术,通过提前下载H5渲染需要的H ...

  4. 使用libswresample库实现音频重采样

    一.初始化音频重采样器 在音频重采样时,用到的核心结构是SwrContext,我们可以通过swr_alloc()获取swr_ctx实例,然后通过av_opt_set_int()函数和av_opt_se ...

  5. 如何构建高效、可观的系统「GitHub 热点速览」

    经典老项目 system-design 教你如何设计一个健壮的系统,新项目 noodle 教你如何提升教育效率,而后者甚至单日获得了 1,600 star,刚开源就获得了 6k+ 的 star. 除了 ...

  6. AcWing 4486. 数字操作题解

    题目描述 给定一个整数 \(n\),你可以对该数进行任意次(可以是 \(0\) 次)变换操作. 每次操作为以下两种之一: 将整数 \(n\) 乘以任意一个正整数 \(x\). 将整数 \(n\) 替换 ...

  7. 踏入数字天地之中 | Metaworld SDK 2.0进化纵览

    ​ ZEGO从未停止对技术边界的探索,我们力图让用户能够更高效.便捷地使用技术去创造价值. 去年8月,ZEGO打造的元宇宙智能互动引擎首次与大家见面,Metaworld SDK作为其中的核心能力组件, ...

  8. [Spring+SpringMVC+Mybatis]框架学习笔记(九):Mybatis主配置文件和映射文件

    第9章 Mybatis主配置文件和映射文件 9.1 用Mybatis进行开发的两种方式 在正式的开发环境中用Mybatis进行开发有两种方式: 1)原始的接口和实现类的方式 缺点: 重复代码太多,sq ...

  9. Linux中的进程页表

    是什么 进程页表是用于管理进程虚拟地址空间和物理内存之间映射关系的数据结构.它记录了进程中每个虚拟页对应的物理页的信息. 什么作用 进程使用进程页表的方式是通过虚拟地址访问内存.当进程访问一个虚拟地址 ...

  10. 智能制造之路—从0开始打造一套轻量级MOM平台之基础平台搭建(Linux部署)

    一.前言 前面我们选定了Admin.net来搭建我们的MOM快速开发平台,本章主要描述.NET6平台的Linux部署,以及记录搭建过程中坑. 本次搭建我们选择某云的轻量应用服务器,系统选择CentOS ...