随着 Go 第一个版本发布的还有一份兼容性说明文档[2] 。该文档承诺,Go 的未来版本会尽可能确保向后兼容性,不会破坏现有程序。
For instance, code that runs under Go 1.2 should be compatible with Go 1.2.1, Go 1.3, Go 1.4, etc., although not necessarily with Go 1.1 since it may use features added only in Go 1.2
此版本中已包含 go tool pprof 命令,它是Google的pprof C++分析器[3] 的一个变种;
同时还包含 go vet 命令(之前的是 go tool vet),它可以报告程序包中可能存在的错误。
Go 1 Release Notes[4]
Go 1.1[5] - 2013 年 5 月:
The most significant improvements are performance-related. We have made optimizations in the compiler and linker, garbage collector, goroutine scheduler, map implementation, and parts of the standard library. It is likely that your Go code will run noticeably faster when built with Go 1.1.
这个版本的 Go 致力于增强语言特性(编译器、垃圾回收机制、映射、goroutine 调度器)与性能。
M 是操作系统线程,P 表示一个处理器(P 的数量不能超过 GOMAXPROCS),其中每个 P 对应一个本地 go 协程队列。 1.1 版本之前,P 的概念没有被引入,go 协程在全局范围通过存在于全局的单个互斥锁管理。 这次改进实现了“任务窃取(work-stealing)”,允许一个 P 处理队列“窃取”另外一个 P 处理队列的协程任务。
(图片来自Go’s work-stealing scheduler[7])
Go 1.0需要在每个函数最后,显式地return(或panic);在Go 1.1中,如果函数的最终语句可以在语法上显示为终止语句,则可以省略最终的“return”语句[8]
增加了竞态检测器[9],提高并发编程的安全性. Go: Race Detector with ThreadSanitizer[10]
Go 1.1 Release Notes[11]
Go 1.2[12] - 2013 年 12 月:
Three-index slices[13]
Go 1.2之前,切片的参数只允许有两个,即 sli[i:j],即初始位置i和(长度的)结束位置j,其cap默认是底层数组的容器,如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
package main
import"fmt"
funcmain(){
var array [10]int sli := array[0:8] slice := array[2:4] //只看头(从哪里切),不看尾,即顾头不顾尾...
Go 1.2 adds new syntax to allow a slicing operation to specify the capacity as well as the length. A second colon introduces the capacity value, which must be less than or equal to the capacity of the source slice or array, adjusted for the origin.
go test 命令支持代码覆盖率报告,并提供新的 go tool cover 命令输出代码测试覆盖率的统计信息. The cover story[15]
One major new feature of go test is that it can now compute and, with help from a new, separately installed “go tool cover” program, display test coverage results.
Go 1.2 Release Notes[16]
Go 1.3 [17]- 2014 年 6 月:
Changes to the runtime have improved the performance of Go binaries, with an improved garbage collector, a new “contiguous” goroutine stack management strategy, a faster race detector, and improvements to the regular expression engine.
堆栈管理在此版本中得到了重要改善。
堆栈现在会分配连续的内存片段[18],并提高了分配效率。这使得 Go 语言在下个版本中将堆栈大小减少到 2KB。
通过 Pool可以复用代码结构,减少分配资源的数量. 该组件随后成为 Go 生态中许多改进的来源,如标准库中的 encoding/json 和 net/http 包,及 Go 社区中的 zap 等包。
更多信息可阅读:
Go: Understand the Design of Sync.Pool[21]
翻译:Go: 理解 Sync.Pool 的设计[22]
改进了channel的实现[23],提升了性能
Go 1.2 与 Go 1.3 版本间 channel 的性能对比:
Go 1.3 Release Notes[24]
Go 1.4[25] - 2014 年 12 月:
The release focuses primarily on implementation work, improving the garbage collector and preparing the ground for a fully concurrent collector to be rolled out in the next few releases. Stacks are now contiguous, reallocated when necessary rather than linking on new “segments”; this release therefore eliminates the notorious “hot stack split” problem.
Android 的官方支持包golang.org/x/mobile随该版本一同发布,使开发者可以仅用 Go 代码编写简单的 Android 应用。
之前用 C 和汇编语言编写的大多数运行时已转换为用 Go 语言实现 && 使用了更精准的垃圾收集器,堆栈大小减少了 10~30%
Prior to Go 1.4, the runtime (garbage collector, concurrency support, interface management, maps, slices, strings, …) was mostly written in C, with some assembler support. In 1.4, much of the code has been translated to Go so that the garbage collector can scan the stacks of programs in the runtime and get accurate information about what variables are active. This change was large but should have no semantic effect on programs.
This rewrite allows the garbage collector in 1.4 to be fully precise, meaning that it is aware of the location of all active pointers in the program. This means the heap will be smaller as there will be no false positives keeping non-pointers alive. Other related changes also reduce the heap size, which is smaller by 10%-30% overall relative to the previous release.
A consequence is that stacks are no longer segmented, eliminating the “hot split” problem. When a stack limit is reached, a new, larger stack is allocated, all active frames for the goroutine are copied there, and any pointers into the stack are updated. Performance can be noticeably better in some cases and is always more predictable. Details are available in the design document.
The use of contiguous stacks means that stacks can start smaller without triggering performance issues, so the default starting size for a goroutine’s stack in 1.4 has been reduced from 8192 bytes to 2048 bytes.
As preparation for the concurrent garbage collector scheduled for the 1.5 release, writes to pointer values in the heap are now done by a function call, called a write barrier, rather than directly from the function updating the value. In this next release, this will permit the garbage collector to mediate writes to the heap while it is running. This change has no semantic effect on programs in 1.4, but was included in the release to test the compiler and the resulting performance.
The implementation of interface values has been modified. In earlier releases, the interface contained a word that was either a pointer or a one-word scalar value, depending on the type of the concrete object stored. This implementation was problematical for the garbage collector, so as of 1.4 interface values always hold a pointer. In running programs, most interface values were pointers anyway, so the effect is minimal, but programs that store integers (for example) in interfaces will see more allocations.
As of Go 1.3, the runtime crashes if it finds a memory word that should contain a valid pointer but instead contains an obviously invalid pointer (for example, the value 3). Programs that store integers in pointer values may run afoul of this check and crash. In Go 1.4, setting the GODEBUG variable invalidptr=0 disables the crash as a workaround, but we cannot guarantee that future releases will be able to avoid the crash; the correct fix is to rewrite code not to alias integers and pointers.
发布 go generate 命令,此命令会扫描//go:generate 指令提供的信息生成代码,简化了代码生成的方式。
Generating code[26]
引入了Internal包
Go 1.4 “Internal” Packages[27]
Go 的项目代码管理工具从 Mercurial 切换为 Git,与此同时,项目也从 Google Code 迁移到了 Github 上
图片来源:Getting to Go: The Journey of Go’s Garbage Collector[35]
调度程序的相关改进允许将默认的 GOMAXPROCS 值(并发执行的 goroutine 的数量)从 1 更改为逻辑 CPU 的数量。在以前的版本中,默认值为 1
Go 1.5 GOMAXPROCS Default[36]
Runtime In Go 1.5, the order in which goroutines are scheduled has been changed. The properties of the scheduler were never defined by the language, but programs that depend on the scheduling order may be broken by this change. We have seen a few (erroneous) programs affected by this change. If you have programs that implicitly depend on the scheduling order, you will need to update them.
Another potentially breaking change is that the runtime now sets the default number of threads to run simultaneously, defined by GOMAXPROCS, to the number of cores available on the CPU. In prior releases the default was 1. Programs that do not expect to run with multiple cores may break inadvertently. They can be updated by removing the restriction or by setting GOMAXPROCS explicitly. For a more detailed discussion of this change, see the design document.
For program-ending panics, the runtime now by default prints only the stack of the running goroutine, not all existing goroutines. Usually only the current goroutine is relevant to a panic, so omitting the others significantly reduces irrelevant output in a crash message. To see the stacks from all goroutines in crash messages, set the environment variable GOTRACEBACK to all or call debug.SetTraceback before the crash, and rerun the program. See the runtime documentation[40] for details.
Updating: Uncaught panics intended to dump the state of the entire program, such as when a timeout is detected or when explicitly handling a received signal, should now call debug.SetTraceback(“all”) before panicking. Searching for uses of signal.Notify may help identify such code.
默认启用vendor目录
sort.Sort 内部的算法进行了改进,运行速度提高了约 10%
In the sort package, the implementation of Sort has been rewritten to make about 10% fewer calls to the Interface’s Less and Swap methods, with a corresponding overall time savings. The new algorithm does choose a different ordering than before for values that compare equal (those pairs for which Less(i, j) and Less(j, i) are false).
Updating: The definition of Sort makes no guarantee about the final order of equal values, but the new behavior may still break programs that expect a specific order. Such programs should either refine their Less implementations to report the desired order or should switch to Stable, which preserves the original input order of equal values.
Go 1.6 Release Notes[41]
Go 1.7[42] - 2016 年 8 月:
context包转正
可以为用户提供处理超时和任务取消的机制
Over the past few years, the golang.org/x/net/context package has proven to be essential to many Go applications. Contexts are used to great effect in applications related to networking, infrastructure, and microservices (such as Kubernetes and Docker). They make it easy to enable cancellation, timeouts, and passing request-scoped data. To make use of contexts within the standard library and to encourage more extensive use, the package has been moved from the x/net repository to the standard library as the context package. Support for contexts has been added to the net, net/http, and os/exec packages. For more information about contexts, see the package documentation and the Go blog post Go Concurrency Patterns: Context.[43]
在过去的几年里,golang.org/x/net/context 包已被证明对许多 Go 应用程序至关重要。上下文在与网络、基础设施和微服务(例如 Kubernetes 和 Docker)相关的应用程序中发挥了重要作用。它们使启用取消、超时和传递请求范围的数据变得容易。为了在标准库中使用上下文并鼓励更广泛的使用,该包已作为上下文包从 x/net 存储库移至标准库。对上下文的支持已添加到 net、net/http 和 os/exec 包中。有关上下文的更多信息,请参阅包文档和 Go 博客文章 Go Concurrency Patterns: Context。
编译时间显着加快
二进制文件大小减少了 20-30%, CPU 时间减少了 5-35%
A new compiler back end, based on static single-assignment form (SSA), has been under development for the past year. By representing a program in SSA form, a compiler may perform advanced optimizations more easily. This new back end generates more compact, more efficient code that includes optimizations like bounds check elimination and common subexpression elimination. We observed a 5–35% speedup across our benchmarks. For now, the new backend is only available for the 64-bit x86 platform (“amd64”), but we’re planning to convert more architecture backends to SSA in future releases.
Most of the engineering effort put into this release went to improvements of the runtime and tooling, which makes for a less exciting announcement, but nonetheless a great release.
Most of its changes are in the implementation of the toolchain, runtime, and libraries. … There are no significant changes to the language specification.
大部分更改都在工具链、运行时和库的实现中,语言规范没有重大变化
go test命令可以缓存测试结果
The go test command now caches test results: if the test executable and command line match a previous run and the files and environment variables consulted by that run have not changed either, go test will print the previous test output, replacing the elapsed time with the string “(cached).” Test caching applies only to successful test results; only to go test commands with an explicit list of packages; and only to command lines using a subset of the -cpu, -list, -parallel, -run, -short, and -v test flags. The idiomatic way to bypass test caching is to use -count=1.
go test命令现在可以缓存测试结果:如果测试的可执行文件和命令行与之前的运行相匹配,并且该运行所查询的文件和环境变量也没有改变,go test将打印之前的测试输出,用字符串”(cached)”代替经过的时间。测试缓存只适用于成功的测试结果;只适用于有明确软件包列表的go test命令;只适用于使用-cpu、-list、-parallel、-run、-short和-v测试标志的子集的命令行。绕过测试缓存的习惯性方法是使用-count=1。
There are many changes and improvements to the toolchain, runtime, and libraries, but two features stand out as being especially exciting: modules and WebAssembly support.
Go modules
根据Go 2018 Survey Results[59]问卷调查,大多数人面临的最大挑战是包管理
This release adds preliminary support for a new concept called “modules,” an alternative to GOPATH with integrated support for versioning and package distribution.
一个副作用是不再支持 go tool vet。使用 go tool vet 的外部工具必须更改为使用 go vet。使用 go vet 而不是 go tool vet 应该适用于所有受支持的 Go 版本。
Go 1.12 Release Notes[64]
Go 1.13[65] - 2019 年 9 月:
优化sync.Pool
sync 包的 Pool 组件得到改进,得其中的资源不会在垃圾回收时被清除(通过新机制里引入的缓存,两次垃圾回收之间没有被使用过的实例才会被清除)
重了逃逸分析逻辑,使得 Go 程序减少了堆上的分配次数
go 命令默认使用 Go module mirror and Go checksum database下载和验证模块
对数字文字的改进
错误换行
默认开启 TLS 1.3
Go 1.13 Release Notes[66]
Go 1.14 [67]- 2020 年 2 月:
Go Module已可用于生产使用
鼓励所有用户迁移到 go modules进行依赖管理
嵌入具有重叠方法集的接口
Per the overlapping interfaces proposal, Go 1.14 now permits embedding of interfaces with overlapping method sets: methods from an embedded interface may have the same names and identical signatures as methods already present in the (embedding) interface. This solves problems that typically (but not exclusively) occur with diamond-shaped embedding graphs. Explicitly declared methods in an interface must remain unique, as before.
This release improves the performance of most uses of defer to incur almost zero overhead compared to calling the deferred function directly. As a result, defer can now be used in performance-critical code without overhead concerns.
goroutines 是异步可抢占的
Goroutines are now asynchronously preemptible. As a result, loops without function calls no longer potentially deadlock the scheduler or significantly delay garbage collection. This is supported on all platforms except windows/arm, darwin/arm, js/wasm, and plan9/.
A consequence of the implementation of preemption is that on Unix systems, including Linux and macOS systems, programs built with Go 1.14 will receive more signals than programs built with earlier releases. This means that programs that use packages like syscall or golang.org/x/sys/unix will see more slow system calls fail with EINTR errors. Those programs will have to handle those errors in some way, most likely looping to try the system call again. For more information about this see man 7 signal for Linux systems or similar documentation for other systems.
实施抢占的结果是,在包括 Linux 和 macOS 系统在内的 Unix 系统上,使用 Go 1.14 构建的程序将接收到比使用早期版本构建的程序更多的信号。这意味着使用 syscall 或 golang.org/x/sys/unix 等软件包的程序将看到更多缓慢的系统调用失败并出现 EINTR 错误。这些程序必须以某种方式处理这些错误,很可能会循环以再次尝试系统调用。有关这方面的更多信息,请参阅 Linux 系统的 man 7 signal 或其他系统的类似文档。
页面分配器更高效
The page allocator is more efficient and incurs significantly less lock contention at high values of GOMAXPROCS. This is most noticeable as lower latency and higher throughput for large allocations being done in parallel and at a high rate.
Internal timers, used by time.After, time.Tick, net.Conn.SetDeadline, and friends, are more efficient, with less lock contention and fewer context switches. This is a performance improvement that should not cause any user visible changes.
Allocation of small objects now performs much better at high core counts, and has lower worst-case latency. Converting a small integer value into an interface value no longer causes allocation. Non-blocking receives on closed channels now perform as well as non-blocking receives on open channels.
现在,小对象的分配在高核心数下表现得更好,并且具有更低的最坏情况延迟。
将小整数值转换为接口值不再导致分配。
现在,关闭通道上的非阻塞接收与开放通道上的非阻塞接收一样好。
编译器/汇编器/链接器的优化
Go 1.15 reduces typical binary sizes by around 5% compared to Go 1.14 by eliminating certain types of GC metadata and more aggressively eliminating unused type metadata.
与 Go 1.14 相比,Go 1.15 通过消除某些类型的 GC 元数据并更积极地消除未使用的类型元数据,将二进制大小减少了约 5%。
This release includes substantial improvements to the Go linker, which reduce linker resource usage (both time and memory) and improve code robustness/maintainability.
Go 1.15包括对 Go 链接器的重大改进,这减少了链接器资源的使用(时间和内存)并提高了代码的稳健性/可维护性。
内置了tzdata包
Go 1.15 包含一个新包 time/tzdata,它允许将时区数据库嵌入到程序中。导入此包(如 import _ “time/tzdata”)允许程序查找时区信息,即使本地系统上没有时区数据库。还可以嵌入时区数据库
Go的LoadLocation 有个问题,其依赖于 IANA Time Zone Database (简称 tzdata)
On Linux, the runtime now defaults to releasing memory to the operating system promptly (using MADV_DONTNEED), rather than lazily when the operating system is under memory pressure (using MADV_FREE). This means process-level memory statistics like RSS will more accurately reflect the amount of physical memory being used by Go processes. Systems that are currently using GODEBUG=madvdontneed=1 to improve memory monitoring behavior no longer need to set this environment variable.
在 Linux 上,运行时现在默认立即向操作系统释放内存(使用 MADV_DONTNEED),而不是在操作系统处于内存压力下时懒惰地释放内存(使用 MADV_FREE)。这意味着像 RSS 这样的进程级内存统计数据将更准确地反映 Go 进程正在使用的物理内存量。当前使用 GODEBUG=madvdontneed=1 来改善内存监控行为的系统不再需要设置此环境变量。
Go 1.12 关于内存释放的一个”改进”[76]
弃用io/ioutil
该包的函数, 挪到了io包和os包
许多其他改进和错误修复
包括构建速度提高了 25%,内存使用量减少了 15%
Go 1.16 Release Notes[77]
Go 1.17[78] - 2021 年 8 月:
As always, the release maintains the Go 1 promise of compatibility. We expect almost all Go programs to continue to compile and run as before.
与往常一样,该版本保持了 Go 1 的兼容性承诺。我们希望几乎所有 Go 程序都能像以前一样继续编译和运行。
go modules 支持“修剪模块图”(Pruned module graphs)
如果模块指定 go 1.17 或更高版本,则模块图仅包含其他 go 1.17 模块的直接依赖关系,而不包括它们完整传递依赖关系
但是会在 go.mod 记录间接依赖的库版本。执行以下命令升级 go mod tidy -go=1.17
Go 1.18 is a massive release that includes new features, performance improvements, and our biggest change ever to the language.
按惯例应该在2月份发布,Delay了一个多月
泛型
千呼万唤,伴随争议终于到来
Type Parameters Proposal[81]
Go Blog提到 It isn’t a stretch to say that the design for parts of Go 1.18 started over a decade ago when we first released Go.,指的可能就是2009年rsc在博客里探讨泛型如何设计[82]
好奇为啥用[]而不是其他语言普遍采用的<>
Rob Pike的担忧[83],建议先不要用泛型,改动 Go 1.18 中的标准库
模糊测试(Fuzzing)
Go is the first major language with fuzzing fully integrated into its standard toolchain
Go Fuzzing[84]
作为代价,fuzzing 会消耗大量内存,影响机器性能,占用也许是几个G的存储空间
Rob Pike对fuzzing的疑虑[85]
Workspaces 工作区
在2021 年用户调查中,反馈最多的挑战是跨多个模块工作。在 Go 1.18 中,使用新的 Go 工作区模式解决了这个问题,使用多个模块将变得简单。