在 1.17 版本中,Go 团队实现了一种使用寄存器而不是堆栈来传递函数参数值和结果值的新方法。大家都知道,堆栈指的是内存中的某块空间。
解读Go语言的2021:稳定为王-InfoQ https://www.infoq.cn/article/eMLshYbKJTEIEiMVzwBJ
2.4 标准库
下面,我们来简要地说一下 Go 语言标准库中的变化。其中大大小小的变更有很多,但从整体来看它们都不是最关键的。因此,作者只会在这里提及那几个新增或废弃的代码包。
2.4.1 新增的 3 个代码包
从 1.16 版本开始,Go 语言的标准库中增加了 runtime/metrics 包。简单来说,这个代码包的出现是为了方便 Go 程序在其运行的时候自行获取它的各种指标。这样的指标有很多,涉及垃圾回收、内存使用、并发调度等。这个代码包在功能上取代了之前已经存在的runtime.ReadMemStats
函数和debug.GCStats
结构体,并且更加的通用和高效。
此外,io/fs 包和 embed 包也都是在 1.16 版本中被引入的。
代码包 io/fs 代表了一种全新的文件系统模型,或者说,它是关于文件系统的一个统一的高层抽象。它的出现使得 Go 语言标准库中的不少代码包都发生了变化,并且出现了一些新的 API。当然了,这些变化都是有利于 Go 语言和开发者的。
而代码包 embed 则主要用于在 Go 程序的可执行文件中嵌入额外的资源,比如:文本文件、图片文件、音视频文件,以及其他的数据文件等等。而且,我们还可以为此指定多个文件,甚至多个目录。这会涉及到注释指令//go:embed
的合理使用。
我在本系列的前一篇文章(即:解读 Go 语言的 2020:变革前夜)当中已经对 io/fs 包和 embed 包有过简要的说明,所以在这里就不再赘述了。对于想用好这几个新包的开发者,作者强烈建议:仔细查阅 Go 标准库的相应文档,并在必要时阅读相关的 Go 语言源码。
2.4.2 废弃 io/ioutil 包
Go 团队现在已经认定,io/ioutil 包是一个定义不清而且难以理解的程序集合。因此,从 Go 语言的 1.16 版本开始,这个包中提供的所有功能(的主要实现代码)都已被迁移到其他的代码包当中(如 io 包和 os 包)。不过,为了保持向后的兼容性,io/ioutil 包会被继续保留,并像以前那样提供正确的功能。下面是关于此的功能迁移列表:
-
io/ioutil.Discard 的功能已移至 io.Discard;
-
io/ioutil.NopCloser 的功能已移至 io.NopCloser;
-
io/ioutil.ReadAll 的功能已移至 io.ReadAll
-
io/ioutil.ReadDir 的功能已移至 os.ReadDir(但要注意,两者返回的第一个结果值的类型不同,前者是[]fs.FileInfo,而后者是[]os.DirEntry);
-
io/ioutil.ReadFile 的功能已移至 os.ReadFile;
-
io/ioutil.TempDir 的功能已移至 os.MkdirTemp;
-
io/ioutil.TempFile 的功能已移至 os.CreateTemp;
-
io/ioutil.WriteFile 的功能已移至 os.WriteFile。
2.5 语法
Go 语言的 1.17 版本中增加了一项微小但强大的改进,即:支持从切片到数组指针的转换。更具体地说,类型为[]T
的切片现在可以被正确地转换为以*[N]T
为类型的数组指针了,如:
不过,需要特别注意的是,如果我们给定的数组指针类型不恰当,那么这里的第二行代码就会立即抛出一个运行时异常(即 panic)。例如,如果我们给定的类型当中的(代表数组长度的)数值大于要被转换的那个切片的实际长度,如代码 (*[6]int)(slice1)
,那么程序就会由于这里抛出的异常而崩溃(如果没有妥善处理的话)。
2.6 关于性能
按照惯例,Go 团队每年都会对 Go 语言在某些方面的性能进行改进。今年当然也不例外。
在 1.16 版本中,Go 语言的链接器在性能方面得到了进一步的提升。在 64 位的 Linux 操作系统上,其链接速度比 1.15 版本快了 20%-25%,同时链接操作所占用的内存空间也减少了 5%-15%。在其他的计算平台上,此类性能提升有过之而无不及。此外,由于更激进的符号修剪,Go 程序经处理后产生的二进制文件通常也更小了。顺便说一下,这里所说的计算平台是计算架构(如 386、amd64、arm 等)和操作系统(如 windows、linux、darwin 等)的组合和统称。其中的 darwin 是 macOS 操作系统在 Go 语言当中的代号。
在 1.17 版本中,Go 团队实现了一种使用寄存器而不是堆栈来传递函数参数值和结果值的新方法。大家都知道,堆栈指的是内存中的某块空间。所以,使用堆栈通常可以不关心各个计算架构(以及不同型号的 CPU)之间的差异。但其缺点也很明显,即性能较差。大家应该也知道,寄存器是 CPU 中的存储器件。因此,使用寄存器的话就不得不去关注计算架构这种更底层的东西了。这显然是更加困难但性能更优的方式。总之,这一新方法让 Go 程序的运行性能提升了大约 5%。并且,Go 程序产出的二进制文件通常也会小 2%左右。目前,在 Linux、macOS 和 Windows 操作系统的 64 位计算结构上,Go 语言都自动启用了此功能。
2.7 其他更新
众所周知,Apple 公司已经推出了自己的 ARM 计算架构的 CPU,并且把它用在了自家的电脑上。因此,一种新的计算架构-操作系统组合(即计算平台)出现了,它就是:darwin/arm64。
以前,在 Go 语言中,iOS 操作系统所对应的计算平台代号是 darwin/arm64。因为在那个时候,Apple 公司只在智能手机 iPhone 和平板电脑 iPad 当中使用 ARM 计算架构的 CPU。然而,今日不同往日,所以 Go 团队在 Go 语言的 1.16 版本中适配了上述新的组合。
他们把 macOS 操作系统对应的计算平台代号确定为 darwin/arm64,而原先的 iOS 操作系统所对应的计算平台代号被重命名为 ios/arm64。也就是说,在 Go 语言的上下文中出现了一个新的操作系统代号:ios。目前,它与 darwin 一起覆盖了 Apple 公司推出的主要操作系统。
另外,Go 1.16 还添加了一个代号为 ios/amd64 的计算平台。这又是一种新的组合。这个计算平台针对的是,在基于 64 位 AMD 计算架构的 macOS 操作系统之上运行的 iOS 模拟器。
随后,在 1.17 版本中,Go 语言又支持了 Windows 操作系统与 64 位 ARM 计算架构的新组合,代号为 windows/arm64。这也可以从侧面体现出,移动计算平台正在与原先的桌面计算平台融合。
好了,以上就是作者针对 Go 语言在 2021 年的主要变化做出的一个简要的梳理。作者认为,对于广大的开发者而言,Go 语言在该年度最喜人的变化莫过于模块管理功能以及相关命令方面的大幅改进。当然了,Go 语言标准库中新增的那三个代码包也很重要。