社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
对每一个开发者来说,Go 的发展历史是必须知道的知识。了解几年来每个发行版本的主要变化,有助于理解 Go 的设计思想和每个版本的优势/弱点。
Go 的第一个版本,带着一份兼容性说明文档来保证与未来发布版本的兼容性,进而不会破坏已有的程序。
第一个版本已经有 go tool pprof 命令和 go vet 命令。 go tool pprof 与 Google 的 pprof C++ profiler 稍微有些差异。go vet(前身是 go tool vet)命令可以检查包中潜在的错误。
垃圾回收:完全串行的标记和清除过程,需要暂停整个程序;
这个 Go 版本专注于优化语言(编译器,gc,map,go 调度器)和提升它的性能。 这个版本也嵌入了竞争检测,在语言中是一个很强大的工具。 重写了 Go 调度器 显著地提升了性能。
垃圾回收:在多核主机并行执行垃圾收集的标记和清除阶段11;
本版本中 test 命令支持测试代码覆盖范围并提供了一个新命令 go tool cover 。
这个版本对栈管理做了重要的改进。栈可以申请连续的内存片段,提高了分配的效率,使下一个版本的栈空间降到 2KB。
栈频繁申请/释放栈片段会导致某些元素变慢,本版本也改进了一些由于上述场景糟糕的分配导致变慢的元素。
这个版本在 sync 包中发布了 Pool。 这个元素允许我们复用结构体,减少了申请的内存的次数,同时也是很多 Go 生态获得改进的根源,如标准库或包里的 encoding/json 或 net/http,还有 Go 社区里的 zap。
Go 团队也对通道作了改进,让它们变得更快。
垃圾回收:运行时基于只有指针类型的值包含指针的假设增加了对栈内存的精确扫描支持,实现了真正精确的垃圾收集
此版本带来了官方对 Android 的支持,golang.org/x/mobile ) 让我们可以只用 Go 代码就能写出简单的 Android 程序。
归功于更高效的 gc,之前用 C 和汇编写的运行时代码被翻译成 Go 后,堆的大小降低了 10% 到 30%。
与版本无关的一个巧合是,Go 项目管理从 Mercurial 移植到了 Git,代码从 Google Code 移到了 Github。
Go 也提供了 go generate 命令通过扫描用 //go:generate 指示的代码来简化代码生成过程。
这个新版本,发布时间推迟了两个月,目的是在以后每年八月和二月发布新版本:
这个版本对 gc 进行了重新设计。归功于并发的回收,在回收期间的等待时间大大减少。
这个版本也发布了运行时追踪,用命令 go tool trace 可以查看。
垃圾回收:实现了基于三色标记清扫的并发垃圾收集器13;大幅度降低垃圾收集的延迟从几百 ms 降低至 10ms 以下;计算垃圾收集启动的合适时间并通过并发加速垃圾收集的过程;
这个版本最重大的变化是使用 HTTPS 时默认支持 HTTP/2。
在这个版本中 gc 等待时间也降低了:
垃圾回收:实现了去中心化的垃圾收集协调器;基于显式的状态机使得任意 Goroutine 都能触发垃圾收集的状态迁移;使用密集的位图替代空闲链表表示的堆内存,降低清除阶段的 CPU 占用14;
这个版本发布了 context 包,为用户提供了处理超时和任务取消的方法。
对编译工具链也作了优化,编译速度更快,生成的二进制文件更小,有时甚至可以减小 20% 到 30%。
垃圾回收:通过并行栈收缩将垃圾收集的时间缩短至 2ms 以内15;
把 gc 的停顿时间减少到了 1 毫秒以下。 其他的停顿时间已知,并会在下一个版本中降到 100 微秒以内。 这个版本也改进了 defer 函数。
垃圾回收:使用混合写屏障将垃圾收集的时间缩短至 0.5ms 以内16;
这个版本增加了一些别名声明。 sync 包新增了一个 Map 类型,是并发写安全的。
垃圾回收:彻底移除暂停程序的重新扫描栈的过程17;
test 包引进了一个新的智能 cache,运行会测试后会缓存测试结果。如果运行完一次后没有做任何修改,那么开发者就不需要重复运行测试,节省时间。
为了加快构建速度,go build 命令现在也维持了一份最近构建包的缓存。
这个版本没有对 gc 做实际的改变,但是确定了一个新的 SLO(Service-Level Objective)
垃圾回收:更新了垃圾收集调频器(Pacer)的实现,分离软硬堆大小的目标18;
Go 1.11 带来了一个重要的新功能:Go modules。module机制的实验性引入,以试图解决长久以来困扰Gopher们的包依赖问题;
第二个特性是实验性的 WebAssembly,为开发者提供了把 Go 程序编译成一个可兼容四大主流 Web 浏览器的二进制格式的能力。这样以后Gopher们可以通过Go语言编写前端应用了。
基于 analysis 包重写了 go vet 命令,为开发者写自己的检查器提供了更大的灵活性。
Go 发布的上一个版本中,对 Go module 的初步支持是默认关闭的,这暗示了它尚遗留着很多实现的问题。事实上,当时 replace 的支持连 module、package、import path 这三个最基本概念都是含混的。
而在 Go 1.12 中,这些问题都得到了解决,Go module 的正式发布又关闭了一条无脑喷 Go 的路径,真正的 Go 用户可以更安心方便地使用 Go。
Go 1.12 的 STW 停顿较 1.11 版本又有明显的缩短。
Go 1.12 的 trace 工具加入了 Minimum Mutator Utilization 图的支持,它可以极其方便地发现 GC 性能受限的情况。
Go 1.12 较为及时地提供了初步的 TLS 1.3 支持。
Timer 与 Deadline 的性能得到了优化,在 connection 上设置 deadline 的代价降低
默认启用 TCP KeepAlive
OS 包开始提供 UserHomeDir 函数,不再需要使用第三方库进行跨平台支持
在 macOS 上调用 File.Sync 并不能确保实际落盘的问题已解决
垃圾回收:使用新的标记终止算法简化垃圾收集器的几个阶段19;
改进了 sync 包中的 Pool,在 gc 运行时不会清除 pool。它引进了一个缓存来清理两次 gc 运行时都没有被引用的 pool 中的实例。
重写了逃逸分析,减少了 Go 程序中堆上的内存申请的空间。
垃圾回收:通过新的 Scavenger 解决瞬时内存占用过高的应用程序向操作系统归还内存的问题20;
现在 Go Module 已经可以用于生产环境,鼓励所有用户迁移到 Module。该版本支持嵌入具有重叠方法集的接口。性能方面做了较大的改进,包括:进一步提升 defer 性能、页分配器更高效,同时 timer 也更高效。
垃圾回收:使用全新的页分配器优化内存分配的速度21;
Go 1.15版本不再对darwin/386和darwin/arm两个32位平台提供支持了。Go 1.15及以后版本仅对darwin/amd64和darwin/arm64版本提供支持。并且不再对macOS 10.12版本之前的版本提供支持。
Go 1.15 包括对链接器的实质性改进,改进了高核心数下小对象的分配,并弃用了X.509 CommonName。 GOPROXY现在支持跳过返回错误的代理,并添加了新的嵌入式 tzdata 包。
由于Go 1.15删除了一些GC元数据和一些无用的类型元数据,Go 1.15编译出的二进制文件size会减少5%左右。
从这个版本起,环境变量 GO111MODULE 的默认值正式修改为 on。
Go1.16 起可以在 go.mod 文件中使用 retract 指令来声明该第三方模块的某些发行版本不能被其他模块使用。
Go 1.16新增go:embed指示符和embed标准库包,二者一起用于支持在在Go二进制文件中嵌入静态文件。
当GODEBUG环境变量包含inittrace=1时,Go运行时将会报告各个源代码文件中的init函数的执行时间和内存开辟消耗情况。
既Go 1.15实现了go linker的第一阶段优化后,Go 1.16中继续实施了对linker的第二阶段优化。优化后的链接器要平均比Go 1.15的快20%-25%,消耗的内存却减少5%-15%。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!