标签 RobPike 下的文章

Rob Pike的“抱怨”与Go的“解药”:直面软件膨胀的四大根源

本文永久链接 – https://tonybai.com/2025/04/27/rob-pike-on-bloat

大家好,我是Tony Bai。

今年年初,Go语言之父、UTF-8编码的发明者Rob Pike的一篇题为”On Bloat”(关于膨胀)的演讲幻灯片(在2024年下旬做的)在技术圈,尤其是在Hacker News(以下简称HN)上,引发了相当热烈的讨论。Pike作为业界泰斗,其对当前软件开发中普遍存在的“膨胀”现象的犀利批评,以及对依赖管理、软件分层等问题的深刻担忧,无疑戳中了许多开发者的痛点。

HN上的讨论更是五花八门,开发者们纷纷从自身经历出发,探讨“膨胀”的定义、成因和后果。有人认为膨胀是“层层叠加的间接性”导致简单修改寸步难行;有人认为是“不必要的功能堆砌”;还有人归咎于“失控的依赖树”和“缺乏纪律的开发文化”。

那么,Rob Pike究竟在“抱怨”什么?他指出的软件膨胀根源有哪些?而作为我们Gopher,Go语言的设计哲学和工具链,能否为我们从纯技术层面提供对抗膨胀的“解药”呢?今天,我们就结合Pike的演讲精髓和HN的热议,深入聊聊软件膨胀的四大根源,并从Go的视角尝试寻找一下应对之道。

“膨胀”的真相:远不止代码大小和运行速度

在深入探讨根源之前,我们需要认识到,“膨胀”并不止是字面意义上我们理解的最终编译产物的大小或者应用的运行速度慢,Pike的观点和HN讨论中的“软件膨胀”体现在多个维度:

  • 复杂性失控: 过度的抽象层次、复杂的依赖关系、难以理解的代码路径,使得维护和迭代变得异常困难。
  • 维护成本剧增: 添加新功能的长期维护成本(包括理解、测试、修复Bug、处理兼容性)远超初次实现的成本,但往往被低估。
  • 不可预测性与脆弱性: 庞大且快速变化的依赖树使得我们几乎无法完全理解和掌控软件的实际构成和行为,任何更新都可能引入未知风险。

下面我们具体看看Pike指出的“膨胀”几个核心根源:

根源一:特性 (Features) —— “有用”不等于“值得”

Pike 指出,我们不断地为产品添加特性,以使其“更好”。但所有特性都会增加复杂性和成本,而维护成本是最大的那部分,远超初次实现。他警示我们要注意“有用谬论” —— 并非所有“有用”的功能都值得我们付出长期的维护代价。

HN讨论也印证了这一点:功能冗余、为了匹配竞品或满足某个高层“拍脑袋”的想法而添加功能、甚至开发者为了个人晋升而开发复杂功能的现象屡见不鲜。

技术层面:Go的“解药”在哪?

  • 简洁哲学: Go从设计之初就强调“少即是多”,鼓励用简单的原语组合解决问题,天然地抵制不必要的复杂性。
  • 强大的标准库: Go 提供了功能丰富且高质量的标准库,覆盖了网络、并发、加解密、I/O 等众多领域,减少了对外部特性库的依赖。很多时候,“自己动手,丰衣足食”(使用标准库)比引入一个庞大的外部框架更符合Go的风格。
  • 关注工程效率: Go的设计目标之一是提高软件开发(尤其是大型项目)的工程效率和可维护性,这促使Go社区更关注代码的清晰度和长期成本。

注:技术层面包括语言、工具以及设计思路和方法。

根源二:分层 (Layering) —— 在错误的层级“打补丁”

Pike 认为,现代软件层层叠加(硬件 -> 内核 -> 运行时 -> 框架 -> 应用代码),当出现问题时,我们太容易在更高的层级通过包装(wrap)来“修复”问题,而不是深入底层真正解决它。这导致了层层叠叠的“创可贴”,增加了复杂性和维护难度。他列举了ChromeOS文件App的例子,并强调要在正确的层级实现功能和修复

在HN的讨论中,有开发者描述的修改按钮颜色需要穿透17个文件和多个抽象层的例子,正是这种“错误分层”或“过度抽象”的生动体现。

技术层面:Go的“解药”在哪?

  • 小接口哲学: Go 鼓励定义小而专注的接口,这使得组件之间的依赖更清晰、更松耦合。当问题出现时,更容易定位到具体的接口实现层去修复,而不是在外部层层包装。
  • 组合优于继承: Go 通过组合(struct embedding)而非继承来实现代码复用,避免了深度继承带来的复杂性和脆弱性,使得在“正确层级”修改代码更易操作。
  • 显式错误处理: if err != nil 的模式强制开发者在调用点处理错误,使得问题更难被“隐藏”到上层去统一“包装”处理,鼓励在错误发生的源头附近解决或添加上下文。

根源三:依赖 (Dependencies) —— 看不见的“冰山”

这是Pike演讲中着墨最多、也最为忧虑的一点。他用数据(NPM 包平均依赖 115 个其他包,每天 1/4 的依赖解析发生变化)和实例(Kubernetes 的复杂依赖图)强调:

  • 现代软件依赖数量惊人且变化极快。
  • 我们几乎不可能完全理解自己项目的所有直接和间接依赖。
  • 依赖中隐藏着巨大的维护成本、Bug 和安全风险
  • 简单的 npm update 或 audit 无法解决根本问题

他强烈建议要理解依赖的成本严格、定期地审视依赖树,并推荐了 deps.dev 这样的工具。

HN 社区对此深有同感,纷纷吐槽“为了一个函数引入整个库”、“脆弱的传递性依赖”、“供应链安全”等问题,并呼唤更好的依赖分析工具。

技术层面:Go的“解药”在哪?

  • Go Modules: 相比 NPM 等包管理器,Go Modules 提供了相对更好的依赖管理机制,包括语义化版本控制、go.sum 校验和、最小版本选择 (MVS) 等,提高了依赖的可预测性和安全性,但也要注意Go module并非完美
  • 强大的标准库: 这是 Go 对抗依赖泛滥的最有力武器。很多功能可以直接使用标准库,避免引入外部依赖。
  • 社区文化: Go 社区相对而言更推崇稳定性和较少的依赖。引入一个大型框架或过多的外部库在 Go 社区通常需要更充分的理由。
  • 工具支持: Go 提供了 go mod graph, go mod why 等命令,可以帮助开发者理解依赖关系。结合 deps.dev,可以在一定程度上实践 Pike 的建议。

根源四:开源模式 (Open Source Development) —— “大门敞开” vs “严格把关”

Pike 对比了两种开源开发模式:

  • “真正的开源方式” (The true open source way): 接受一切贡献 (Accept everything that comes)。他认为这是膨胀和 Bug 的巨大来源
  • 更好的方式: 设立严格的代码质量、标准、评审、测试、贡献者审查等“门槛”,对允许合入的内容有标准。这种方式维护成本低得多。

他暗示 Go 项目本身更倾向于后者,强调“先做好再提交”(make it good before checking it in)。可能很多Gopher也感受到了这一点,Go项目本身对代码质量的review非常严格,这一定程度上也“延缓”了一些新特性进入Go的时间点。

HN 的讨论中也涉及了类似 “Bazaar vs Cathedral” 的模式对比,但观点更加复杂,认为现实中的项目往往处于两者之间的某个位置,并且“完全不接受外部贡献”也并非良策。

技术层面:Go的“解药”在哪?

  • Go 自身的开发模式: Go 语言本身(由 Google 主导)的开发流程相对严谨,对代码质量和向后兼容性有较高要求,可以看作是“严格把关”模式的体现。
  • 标准库的设计: Go 标准库的设计精良、接口稳定,为开发者提供了一个高质量的基础平台,减少了对外部“随意贡献”的依赖。
  • 社区项目实践: 观察 Go 社区一些知名的开源项目,其贡献流程和代码标准通常也比较严格。

反思与现实:Go 也非万能,“警惕与纪律”仍是关键

虽然 Go 的设计哲学和工具链在对抗软件膨胀方面提供了许多“天然优势”和“解药”,但我们必须清醒地认识到,Go 语言本身并不能完全免疫膨胀

正如 Pike 在其“建议”(Advice) 中反复强调的,以及 HN 讨论中部分开发者指出的,最终软件的质量很大程度上取决于开发者和团队的“警惕与纪律” (vigilance and discipline)

  • 我们是否真正理解并避免了增加不相称成本的特性
  • 我们是否努力在正确的层级解决问题
  • 我们是否审慎地评估和管理了每一个依赖
  • 我们是否坚持了高标准的开发和评审流程

如果缺乏这些,即使使用 Go,项目同样可能变得臃肿、复杂和难以维护。同时,HN 讨论也提醒我们,软件膨胀背后还有更深层次的组织、文化和经济因素,这些往往超出了单纯的技术和开发者纪律所能解决的范畴。

小结:拥抱 Go 的简洁,但需务实前行

Rob Pike 的“抱怨”为我们敲响了警钟,Hacker News 的热议则展现了软件膨胀问题的复杂性和普遍性。它确实是我们在工程实践中需要持续对抗的“熵增”现象。

Go 语言以其简洁、显式、组合的设计哲学,以及强大的标准库和相对稳健的依赖管理,在技术层面上,为我们提供了对抗膨胀的有力武器。理解并拥抱这些 Go 的“基因”,无疑能在一定程度上帮助我们构建更健康、更可持续的软件系统。

当然,Pike 的观点也并非金科玉律。有批评者指出,他的视角可能带有一定的“NIH(非我发明)倾向”,并且存在两个关键的“盲点”:

  1. 忽视了“不使用依赖”同样是巨大的技术债。 每一行自写的代码都需要永远维护。
  2. 现实中的选择往往不是“使用依赖 vs 自己实现”,而是“使用依赖 vs 根本不做这个功能”。 面对复杂的合规要求(如 ADA、GDPR)、第三方集成或 FIPS 认证等,从零开始构建的成本(可能需要数百人年)往往让“自己实现”变得不切实际。为了让产品能够及时上线并满足用户(哪怕是 Pike 本人可能也在使用的“缓慢”网站)的需求,引入依赖和一定的“膨胀”有时是必要且务实的选择。

注:“NIH(非我发明)倾向”是一种心理现象,指的是人们对他人提出的想法或创新持有偏见,通常因为这些想法不是自己发明的。这种倾向使得人们倾向于低估或拒绝其他人的创意,尽管这些创意可能是有价值的。

这种批评也提醒了我们,虽然 Pike 对简洁和纪律的呼吁值得我们高度重视,但在真实的商业环境和复杂的工程约束下,我们必须做出务实的权衡。纯粹的技术理想有时需要向现实妥协。

最终,我们每一位 Gopher 都需要在理解 Go 简洁之道的同时,保持批判性思维和务实态度。 在日常的每一个决策中,审慎地权衡简单与复杂、理想与现实、引入依赖与自主掌控,才能在这场与“膨胀”的持久战中,找到最适合我们项目和团队的平衡点,交付真正有价值且可持续的软件。

你如何看待 Rob Pike 对软件膨胀的观点?你认为他的批评切中要害,还是忽视了现实的复杂性?欢迎在评论区分享你的思考与实践!

参考资料

  • Rob Pike – On Bloat – https://docs.google.com/presentation/d/e/2PACX-1vSmIbSwh1_DXKEMU5YKgYpt5_b4yfOfpfEOKS5_cvtLdiHsX6zt-gNeisamRuCtDtCb2SbTafTI8V47/pub?slide=id.p
  • HN:On Bloat – https://news.ycombinator.com/item?id=43045713
  • Pike is wrong on bloat
  • On Bloat – https://commandcenter.blogspot.com/2025/02/on-bloat-these-are-slides-from-talk-i.html

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求,请扫描下方公众号二维码,与我私信联系。

Go 1.24中值得关注的几个变化

本文永久链接 – https://tonybai.com/2025/02/16/some-changes-in-go-1-24

北京时间2025年2月12日,恰逢中国传统元宵佳节,远在美国的Go团队正式发布了Go 1.24的第一个版本Go 1.24.0。这也是Go团队在更换Tech Leader为Austin Clements后发布的首个大版本。

按照惯例,每次Go大版本发布时,我都会撰写一篇“Go 1.x中值得关注的几个变化”的文章。自2014年的Go 1.4版本起,这一系列文章已经持续了11年。

不过,随着从Go 1.17版本开始引入的“Go 1.x新特性前瞻”系列以及针对特定技术特性的专题文章,“Go 1.x中值得关注的几个变化”系列文章的形式也在不断演变。原先的“Go 1.x中值得关注的几个变化”可以理解为被目前的“Go 1.x新特性前瞻” + “特定技术特性文章” + “Go 1.x中值得关注的几个变化”所替代。

不过,随着从Go 1.17版本开始引入的“Go 1.x新特性前瞻”系列以及针对特定技术特性的专题文章,“Go 1.x中值得关注的几个变化”系列的形式也在不断演变。原先的“Go 1.x中值得关注的几个变化”已逐渐被目前的“Go 1.x新特性前瞻” + “特定技术特性文章” + “Go 1.x中值得关注的几个变化(新版)”所替代。希望各位读者能够理解这种变化,“Go 1.x中值得关注的几个变化”系列依然会延续,但文章中将不再进行细致的分析,因为这些内容已经在之前的前瞻和专题文章中讨论过了。

好了,言归正传,我们来说说Go 1.24!

1. 语言变化

正如Go一贯所做的,新版Go 1.24.0继续遵循Go1的兼容性规范。使用Go 1.24.0,你可以顺利编译和运行你用Go 1.11编写的代码。相信许多Gopher正是因为这一点而喜欢上Go,就像下面这位Gopher在Go 1.24发布后所表现出的惊喜一样:

不过,正如Go一贯所做的那样,在语法特性方面,Go显得十分“吝啬”。在Go 1.18大方地引入了泛型之后,Go团队又恢复了这种“吝啬”的风格。在Go 1.24的发布说明中,那短短的一行字充分展现了这一特点:

我们看到,Go 1.24仅仅是将Go 1.23版本中的实验特性“带有类型参数的类型别名”转正了,成为了默认特性。当然你仍然可以GOEXPERIMENT=noaliastypeparams显式关闭它。关于这个特性的具体内容,我们多次说过了,大家可以到《Go 1.24新特性前瞻:语法、编译器与运行时》温习一下它的具体内容。

不过这种“吝啬”也是很多Gopher所期望的,当年Go语言之父Rob Pike在“Simplicity is Complicated”演讲中提到的如下权威观点,影响了诸多Gopher,当然也包括我:

因此,在正在如火如荼的“spec: reduce error handling boilerplate using ?”的讨论中,就当前的情况来看,我也倾向于保持现状

2. 编译器与运行时

在2024年中旬,Fasthttp的作者、VictoriaMetrics的联合创始人Aliaksandr Valialkin曾因Go加入自定义函数迭代的特性而发文抱怨“Go正在朝着错误的方向演进”。不过他也提到,如果Go团队专注于提升Go的性能,而不是在与社区争论一些“华而不实”的语法糖,可能会赢得更多开发者的青睐:

尽管Go 1.24尚未添加对SIMD的官方支持,但引入的优化显然不会让Aliaksandr Valialkin失望。首当其冲的就是对map底层实现的优化——使用更为高效的Swiss Table。关于Swiss Table及Go 1.24重写map的思路,可以参考我的《Go map使用Swiss Table重新实现,性能最高提升近50%》一文。根据文中的实测结果,新版基于Swiss Table的map在多数测试项中表现出显著的性能提升,有些甚至接近50%!

当然,基于Swiss Table的map实现仍在不断完善,其实现者Michael Pratt将持续进行打磨和优化:

参与Go Swiss Table重写方案讨论,并提供参考实现之一的CockroachDB CTO Peter Mattis,也在X.com上分享了新map设计和实现的诞生过程与优势,大家可以阅读以加深理解。

此外,Go 1.24还优化了runtime内部的锁实现,新实现在高竞争情况下取得了显著的可扩展性提升,而不是像Go 1.24之前的实现那样随线程数增加而急剧下降。基准测试表明,在GOMAXPROCS=20时,性能提升达3倍。

更多编译器和运行时的变化,可以参考《Go 1.24新特性前瞻:语法、编译器与运行时》。

Go 1.24版本在编译器和运行时方面的优化投入和勇于改变,正是Go社区所期望的。相信后续版本在这方面的持续投入不会让Aliaksandr Valialkin失望。

3. 工具链

Go团队在Go工具链上的投入和结果一直被Go社区认可和赞扬!《Go 1.24新特性前瞻:工具链和标准库》一文中有对Go 1.24工具链变化的详细介绍,但在这里我还是要再次提及其中的三个变化。

go.mod增加tool指示符,支持对tool的依赖管理

借用《Go工具链版本已不由你定:go和toolchain指令详解》中的那幅图:

Go的目标显然是要实现对Go应用所依赖“全要素”进行版本管理”,涵盖Go版本、工具链版本、第三方包版本以及依赖工具版本的管理。而Go 1.24在go.mod中增加tool指示符就是要实现对依赖工具的版本进行管理。增加tool指示符后,你可以像管理第三方包版本那样,使用go get -tool对依赖的tool的版本进行管理,go install tool对tool进行安装,并支持一个tool同时存在多个版本在本地,这是由于通过go.mod管理的依赖的tool会被像module那样缓存在本地构建缓存中(go build cache)。

btw,再说说go 1.24对toolchain依赖管理和选择的改善。即便看了《Go工具链版本已不由你定:go和toolchain指令详解》一文,很多Gopher还是可能因为gotoolchain决策的复杂性和参与要素的众多而感到困惑,Go 1.24增加了GODEBUG=toolchaintrace=1可以输出做出决策的过程日志,告诉你Go为何会选择某个特定的toolchain版本。

go vet的增强

在Go 1.24中,go vet的功能有了较大变化,新增或增强了如下一些分析器(analyzer):

  • 新增测试分析器

可以检测test、fuzz test、基准测试和example test中的常见错误,避免因命名、签名错误或引用不存在的标识符而导致测试无法运行。

  • printf分析器增强

新增对fmt.Printf(s)的检查,如果这类调用中格式字符串并非常量且没有传入其他参数,则提醒用户使用fmt.Print。

  • buildtag分析器增强

新增对无效Go主版本构建约束的检测,避免错误引用次版本号。例如,如果你使用//go:build go1.23.1,该分析器会提醒你应该使用//go:build go1.23。

  • copylock分析器增强

增强对经典三段式for循环中包含sync.Locker的变量复制的不安全操作的诊断,防止锁的复制带来的潜在问题。这也是Go 1.23修正loopvar语义后避免Go用户误用的一个防卫手段。

新增GOCACHEPROG

另一个大家可能忽视的值得关注的改变是新增了GOCACHEPROG环境变量。

Go语言的cmd/go工具已经具备了强大的缓存支持,但其缓存机制仅限于基于文件系统的缓存。这种缓存方式在某些场景下效率不高,尤其是在CI(持续集成)环境中,用户通常需要将GOCACHE目录打包和解压缩,这往往比CI操作本身还要慢。此外,用户可能希望利用位于网络上的共享缓存(比如S3)或公司内部的P2P缓存协议来提高缓存效率,但这些功能并不适合直接集成到cmd/go工具中。

为了解决上述问题,Brad Fitzpatrick提出了一个新的环境变量GOCACHEPROG,类似于现有的GOCACHE变量。通过设置GOCACHEPROG,用户可以指定一个外部程序,该程序将作为子进程运行,并通过标准输入/输出来与cmd/go工具进行通信。cmd/go工具将通过这个接口与外部缓存程序交互,外部程序可以根据需要实现任意的缓存机制和策略。其大致结构如下:

显然一旦可以在云上存储build cache,也能缓解一下Go用户抱怨本地缓存过大的问题。当然从实际情况来看(我的本地环境),go build cache还不是最大的:

$go env|grep CACHE
GOCACHE='/Users/tonybai/Library/Caches/go-build'
GOCACHEPROG=''
GOMODCACHE='/Users/tonybai/Go/pkg/mod'
$cd /Users/tonybai/Library/Caches/go-build
$du -sh
155M    .

$cd /Users/tonybai/Go/pkg/mod
$du -sh
7.0G

我们看到在我本地的环境中,go build cache和go module cache的size相比,简直是不值得一提,所以说如果后续要有个GOMODCACHEPROG就更好了,我也十分希望能将go module cache搬移到云端(比如S3)中,甚至可以让组织内的Gopher共享这些go module cache(当然要区分不同arch和os)。

更多关于工具链的变化,可以参考《Go 1.24新特性前瞻:工具链和标准库》。

4. 标准库

Go标准库向来是变化的大户,这里我显然不会列出所有变化,甚至一些值得关注的变化,比如:json包增加对omitzero选项的支持新增weak包和weak指针等,也都在新特性前瞻或技术专题性文章中有过详细说明。

这里要说的是Go对fips 140-3合规性的支持,因为这个最终版本与当初新特性前瞻时有所变化。

基于最新的Go fips 140-3文档,我们可以得到关于fips 140-3使用方法的说明,这里简要梳理如下:

  • Go 1.24及更高版本开始,Go二进制文件可以原生运行在FIPS 140-3合规模式下,不必依赖注入boringssl等第三方C++包。
  • Go新增了的一个特殊的Go加密模块 (Go Cryptographic Module),其下有一组新增的标准库包(位于crypto/internal/fips140/…下),实现了 FIPS 140-3批准的算法。这个cryptographic module的版本当前为v1.0.0,目前正在接受CMVP认证实验室的测试。

Go引入了GOFIPS140环境变量,用于go build、go install和go test命令,以选择要链接到可执行程序中的Go加密模块版本。该环境变量有三类可选值:

  • off (默认): 使用标准库中的crypto/internal/fips140/…包。
  • latest: 类似off,但默认启用FIPS 140-3模式。
  • v1.0.0: 使用Go加密模块 v1.0.0 版本(在Go 1.24中首次发布,并在2025年初冻结),默认启用FIPS 140-3模式。

在运行时,可以通过GODEBUG=fips140=xxx来控制上述编译到Go中的Go cryptographic module是否运行在FIPS 140-3模式下,默认是off。

当使用GODEBUG=fips140=on时,Go运行时将会启用Go cryptographic module的FIPS 140-3模式。启用后,Go加密模块会执行以下操作:

  • 完整性自检: 在init阶段,会验证模块对象文件的校验和,确保代码未被篡改。
  • 已知答案自检: 根据FIPS 140-3指南,在init阶段或首次使用时,对算法进行已知答案测试。
  • 密钥一致性测试: 对生成的密钥进行配对一致性测试 (这可能导致某些密钥类型生成速度减慢,特别是临时密钥)。
  • crypto/rand.Reader改进: 使用NIST SP 800-90A DRBG,并从平台CSPRNG获取随机字节混合到输出中。
  • crypto/tls限制: 仅协商符合NIST SP 800-52r2 的协议版本、密码套件、签名算法和密钥交换机制。
  • crypto/rsa.SignPSS限制: 使用PSSSaltLengthAuto时,盐的长度会被限制为哈希的长度。

当使用GODEBUG=fips140=only时,不符合FIPS140-3的加密算法会返回错误或者panic。但是此模式仅为尽力而为,不保证符合所有的FIPS 140-3要求。

不过大家要知道的是:在Go 1.24版本中,GODEBUG=fips140=on和only在OpenBSD、Wasm、AIX和32位Windows平台上暂不受支持。

另外要想要检测FIPS 140-3模式是否已经激活,可以调用crypto/fips140.Enabled函数。

之前,一些场合用户使用BoringCrypto模块来实现某些FIPS 140-3算法的机制仍然可用,但已不被官方支持,并计划在未来版本中移除。另外要知道Go+BoringCrypto与原生FIPS 140-3模式并不兼容。这也是Microsoft Go依旧宣称将保留自己维护的符合fips140-3的Go版本的原因

5. 其他

最后重点说说WebAssembly port。

Go从Go 1.11版本开始通过js/wasm增加了对编译到Wasm的支持。Go 1.21版本又增加了对WASI的支持(GOOS=wasip1),Go 1.24版本中,Go对Wasm的支持又有了新的特性。在Go 1.24发布没多久,Cherry Mui便在官博发表了名为“Extensible Wasm Applications with Go”的介绍Go 1.24中WebAssembly新特性的文章,文章介绍了Go 1.24对Wasm的支持程度以及一些限制。这里也参考了这篇文章,简单梳理一下Cherry给出的内容要点。

Go 1.24引入了新的编译器指示符go:wasmexport,允许将Go函数导出,以便从Wasm模块外部(通常是从运行Wasm运行时的主机应用程序)调用。该指示符指示编译器将带注释的函数作为Wasm导出提供,在生成的Wasm二进制文件中可用,比如:

//go:wasmexport add
func add(a, b int32) int32 { return a + b }

这样,Wasm模块将具有一个名为add的导出函数,可以从主机调用。

这是如何实现的呢?Cherry告诉我们这是通过构建一种名为WASI Reactor的Wasm模块来实现的。WASI Reactor是一种持续运行的WebAssembly模块,可以多次调用以响应事件或请求。与在主函数完成后终止的“命令”模块不同,reactor实例在初始化后保持活动状态,其导出保持可访问状态。

在Go 1.24中,要构建一个WASI reactor需要使用下面命令:

$GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o reactor.wasm

该构建命令指示链接器不生成_start函数(wasm命令模块的入口点),而是生成_initialize函数(执行运行时和包初始化)以及任何导出的函数及其依赖项。_initialize函数必须在任何其他导出函数之前调用。而main函数不会自动调用。

go:wasmexport指示符和reactor构建模式允许通过调用基于Go的Wasm代码来扩展应用程序。这对于采用Wasm作为具有明确定义接口的插件或扩展机制的应用程序特别有价值。通过导出Go函数,应用程序可以利用Go Wasm模块提供功能,而无需重新编译整个应用程序。此外,构建为reactor可确保可以多次调用导出的函数而无需重新初始化,使其适用于长时间运行的应用程序或服务。

次卧,Go 1.24还放宽了对可用于go:wasmimport函数的输入和结果参数类型的限制。例如,可以传递bool、string、指向int32的指针或指向嵌入structs.HostLayout并包含受支持字段类型的结构体的指针,这使得Go Wasm应用程序可以用更自然的方式编写,并消除了不必要的类型转换。

不过,go:wasmexport当前也有局限性,首先,Wasm 是单线程架构,没有并行性。go:wasmexport标识的函数可以生成新的goroutine。但是,如果函数创建了后台goroutine,则当go:wasmexport指示的函数返回时,它将不会继续执行,直到回调到基于Go的Wasm模块。

另外,尽管Go 1.24中放宽了一些类型限制,但对于可与go:wasmimport和go:wasmexport函数一起使用的类型仍然存在限制。比如由于客户端的64位体系结构和主机的32位体系结构之间的不匹配,我们无法传递内存中的指针。例如,go:wasmimport指示的函数不能采用指向包含指针类型字段的结构体的指针。

但不可否认的是go:wasmexport的支持,让Go更稳固了自己成为主流wasm开发语言之一的位置,虽然还有各种不足。近期Docker之父的初创公司Dagger就发博客宣称使用了Go+WebAssembly重写了其Dagger Cloud的前端

6. 小结

Go 1.24的发布,标志着Go语言在保持其核心理念——简洁与兼容性的同时,进入了一个新的发展阶段。这个版本没有在语法上大刀阔斧,而是将重心放在了底层性能优化、工具链完善和新兴技术布局上,展现出Go团队务实且具有前瞻性的发展策略。同时,Go 1.24也可以看成是一个承上启下的版本。它既巩固了Go语言在性能和工具链方面的优势,又为未来的发展方向做出了积极的布局。Go语言正以稳健的步伐,朝着更高效、更安全、更具适应性的方向迈进。我们可以期待,在未来的版本中,Go将继续在云原生计算、WebAssembly、AI应用等领域发挥更大的作用,为开发者带来更多的惊喜。

借此文章插播一条国内Go社区的news!

近期GoCN社区发文“Farewell Go,Hello AI:是时候说再见了”和所有国内Go开发人员分享了“GoCN社区将正式转型升级为ThinkInAI社区”,全面拥抱AI的决定!这也意味国内最大Go技术社区的退出,最大Go技术大会GopherChina的正式落幕!除了AI是热门赛道这一原因之外,文章也给出了Go技术分享遇到瓶颈的说法:

不过就像文中所说的“这是任何技术发展到成熟阶段的必然现象”,在评论中一些Gopher也提到:一个技术不再被更多讨论是成熟的标志

这其实与我在《2024年Go语言盘点:排名历史新高,团队新老传承》一文中表达的Go演进趋势不谋而合!Go真的进入了成熟期了!

GoCn不在了,但go在国内的传播和使用依然会继续。请继续关注诸如Gopher Daily、我的公众号以及国内其他诸如像鸟窝老师的blog以及公众号,了解Go的最新动态以及技术理解。

最后感谢AstaXie(谢孟军)对国内Go社区发展所做出的卓越贡献,我也因有幸多次参与GopherChina以及会上分享而感到无比自豪。


Gopher部落知识星球在2025年将继续致力于打造一个高品质的Go语言学习和交流平台。我们将继续提供优质的Go技术文章首发和阅读体验。并且,2025年将在星球首发“Go陷阱与缺陷”和“Go原理课”专栏!此外,我们还会加强星友之间的交流和互动。欢迎大家踊跃提问,分享心得,讨论技术。我会在第一时间进行解答和交流。我衷心希望Gopher部落可以成为大家学习、进步、交流的港湾。让我相聚在Gopher部落,享受coding的快乐! 欢迎大家踊跃加入!

img{512x368}
img{512x368}

img{512x368}
img{512x368}

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格6$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻) – https://gopherdaily.tonybai.com

我的联系方式:

  • 微博(暂不可用):https://weibo.com/bigwhite20xx
  • 微博2:https://weibo.com/u/6484441286
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • Gopher Daily归档 – https://github.com/bigwhite/gopherdaily
  • Gopher Daily Feed订阅 – https://gopherdaily.tonybai.com/feed

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言进阶课 AI原生开发工作流实战 Go语言精进之路1 Go语言精进之路2 Go语言第一课 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats