泛型是双刃剑?Go1.18 编译会慢近 20%

大家好,我是煎鱼。

目前 Go 的泛型已经在稳定推进的过程,在 Go1.18 将会释出正式的第一版。不过前两天我看到 @danscales 提出的《cmd/compile: Go 1.18 compile time may be about 18% slower than Go.17 (largely from changes due to generics)》。

作者表示在 Go1.18 有了泛型后,编译速度将会变慢,虽然不意外,说明副作用还是有的,升级需谨慎。

以下为修整后概括的原文信息。

性能分析

这个测试主要是测试 Go 泛型对 Go 编译器带来的影响,并没有输入大量的测试用例,是最简单的比较,仅代表大部分的差异。

比较的内容是 Go 泛型的 -G=0 和 -G=3 模式下的编译时间。

分别代表以下含义:

  • -G=0 模式:默认不打开泛型的模式。
  • -G=3 模式:打开泛型的模式。

Go 1.18 中的 -G=0 模式和 Go 1.17 模式的比较显示,由于非泛型的变化,编译器的速度可能降低了~1%(因为 -G=0 模式不支持泛型)。

Go 1.18 的编译时间可能比 Go 1.17 慢 15-18%,这主要是由于实现泛型所带来的变化,也就是 Go1.18 开启泛型下,编译时间会变慢。

差异在哪

大部分的差异是由于新的编译器前端处理,因为 SSA 后端对于泛型完全没有变化。

  • 在 -G=0 模式下(用于 Go 1.18 之前的所有编译器):有一个语法分析器,创建 ir.Node 节点树的 noder 阶段,以及标准类型检查器。
  • 在 -G=3 模式下:有相同的语法分析器,但程序首先由 types2(支持泛型)进行类型检查。

在通过 -G=3 模式打开泛型后,会有一个 noder2 阶段,使用语法信息和 types2 类型检查器的类型信息创建 ir.Node 节点树。在一次运行中,noder+ types1-typechecking 的开销总和约为 4%,而 types2-typechecker+noder2 的总和为 14%。

可以看到大部分的速度下降是由于改变了编译前端处理(并不意外)。

总结

可以明确的是,在打开泛型后,Go1.18 编译时间可能会慢 15-18%,Go 官方将计划在 Go 1.19 中减少这种额外的开销。

泛型的双刃剑初见,后续不管是编译时间、执行时间(预计不会减缓)、泛型的滥用、最佳实践等,都值得我们去讨论和关注。

欢迎大家在评论区讨论和交流:)



go

110 Words

2021-12-31 12:55 +0800