vlambda博客
学习文章列表

Go语言10年版本演进 (2012.03--2022.03)

 

Go 1.0[1]  - 2012 年 3 月:


随着 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 调度器)与性能。


下面是改进的图例:(图片来自Go 1.1 performance improvements–Dave Cheney[6])


Go语言10年版本演进 (2012.03--2022.03)

Go语言10年版本演进 (2012.03--2022.03)




重新编写后的Go的调度器性能有了显著提高。调度器目前的设计如下:

M 是操作系统线程,P 表示一个处理器(P 的数量不能超过 GOMAXPROCS),其中每个 P 对应一个本地 go 协程队列。 1.1 版本之前,P 的概念没有被引入,go 协程在全局范围通过存在于全局的单个互斥锁管理。 这次改进实现了“任务窃取(work-stealing)”,允许一个 P 处理队列“窃取”另外一个 P 处理队列的协程任务。

(图片来自Go’s work-stealing scheduler[7])


Go语言10年版本演进 (2012.03--2022.03)

Go语言10年版本演进 (2012.03--2022.03)




  • 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"

func main(){

var array [10]int
sli := array[0:8]
slice := array[2:4] //只看头(从哪里切),不看尾,即顾头不顾尾...

fmt.Println(cap(sli)) //10
fmt.Println(cap(slice)) //8

}


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.

即之前的slice := array[2:4] 等价于 slice := array[2:4:10],在Go 1.2中因为引入了新的语法,即支持第三个参数,可以调整切片的容量。

“第二个冒号引入容量值,该值必须小于或等于源切片或数组的容量”

slice := array[2:4:7]的cap为 7-2=5


如果第一项不写,[:i:j],即认为是0

更多细节参考设计文件[14]


  • 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。


同时改进了某些组件中堆栈的错误拆分所导致的性能下降问题,此类问题会在堆栈密集分配/释放状态下出现。以下 json 包的例子展示了性能对于堆栈大小的相关度:

Go语言10年版本演进 (2012.03--2022.03)

引入连续堆栈的机制修复了这类组件的性能问题。下面是另一个 html/template 包的例子,它也展示出了性能对于堆栈大小的敏感度:

Go语言10年版本演进 (2012.03--2022.03)


更多信息可阅读:

How Does the Goroutine Stack Size Evolve?[19]

翻译:Go: Goroutine 的堆栈大小是如何演进的[20]


  • 发布了 sync 包的 Pool 组件

通过 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语言10年版本演进 (2012.03--2022.03)




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.

该版本主要侧重于实现工作、改进垃圾收集器并为在接下来的几个版本中推出的完全并发收集器奠定基础。堆栈现在是连续的,在必要时重新分配,而不是链接到新的“段”;因此,此版本消除了臭名昭著的“热堆栈拆分”问题。


  • For-range loops支持新语法


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import "fmt"

func main() {

sli := []string{"shandong", "zhejiang", "guangdong", "jiangsu"}

for k, v := range sli {
fmt.Println("k-v:", k, v) //go 1.3及之前的For-range loops
}

for range sli {
fmt.Println("从1.4开始这种写法是可以通过编译的")
}

}


  • 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 上


Go 1.4 Release Notes[28]





Go 1.5[29] - 2015 年 8 月:



从该版本开始,Go的发布时间延迟两个月,从之前的每年6月和12月 调整为每年 8 月和 2 月发布新版本:

Go Release Cycle[30]


Go语言10年版本演进 (2012.03--2022.03)


图片来源[31]


  • 垃圾回收器[32]被完全重新设计实现

Go 1.5 concurrent garbage collector pacing[33]

Go GC: Latency Problem Solved[34]

归功于基于并发的回收器,垃圾回收延迟被显著降低。

以下来自于 Twitter 生产环境服务器的例子,其中 GC 延迟从 300 毫秒降低到 30 毫秒:


Go语言10年版本演进 (2012.03--2022.03)


图片来源: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.


  • go tool trace

可以在运行时可视化跟踪程序

追踪信息可在测试或运行期间生成,展示在浏览器窗口中


Go语言10年版本演进 (2012.03--2022.03)


Go Execution Tracer[37]


  • map语法的更改

由于疏忽,允许从slice literals中省略元素类型的规则未应用于map。在1.5版本得到了修正

以下两种定义map的方式从1.5及之后都可以(即可以省略Point的类型)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

func main() {

type Point struct {
a float64
b float64
}

m1 := map[Point]string{
Point{29.935523, 52.891566}: "Persepolis",
Point{-25.352594, 131.034361}: "Uluru",
Point{37.422455, -122.084306}: "Googleplex",
}

m2 := map[Point]string{
{29.935523, 52.891566}: "Persepolis",
{-25.352594, 131.034361}: "Uluru",
{37.422455, -122.084306}: "Googleplex",
}

_, _ = m1, m2

}



Go 1.5 Release Notes[38]






Go 1.6 [39]- 2016 年 2 月:



  • 增加对于 HTTP/2 协议的默认支持

  • 再一次降低了垃圾回收器的延迟

  • runtime改变了打印程序结束恐慌的方式。现在只打印发生panic的 goroutine 的堆栈,而不是所有现有的 goroutine

(可以使用 GOTRACEBACK 环境变量或调用 debug.SetTraceback 函数来配置此行为。对搞清楚当前程序一共起了多少个goroutine还是很有用的~)

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.

过去一年一直在开发基于静态单一赋值形式 (SSA) 的新编译器后端。通过以 SSA 形式表示程序,编译器可以更轻松地执行高级优化。这个新的后端生成更紧凑、更高效的代码,包括边界检查消除和公共子表达式消除等优化。我们在基准测试中观察到了 5-35% 的加速。目前,新后端仅适用于 64 位 x86 平台(“amd64”),但我们计划在未来版本中将更多架构后端转换为 SSA。

编译器前端使用一种新的、更紧凑的导出数据格式,并更有效地处理导入声明。虽然编译器工具链中的这些变化大多是不可见的,但用户已经观察到编译时间显着加快,二进制文件大小减少了 20-30%。

为 crypto/sha1, crypto/sha256, encoding/binary, fmt, hash/adler32, hash/crc32, hash/crc64, image/color, math/big, strconv, strings, unicode, and unicode/utf16包的实现带来了 10% 以上的提升

  • 垃圾收集器的加速和标准库的优化

程序应该运行得更快一些。与 Go 1.6 相比,具有许多空闲 goroutine 的程序将经历更短的垃圾收集暂停。

  • 改进了 go tool trace



Go 1.7 Release Notes[44]





Go 1.8[45] - 2017 年 2 月:



  • 优化编译

CPU 时间在 32 位 ARM 系统上减少了 20-30%, 还针对 64 位 x86 系统进行了一些适度的性能改进。编译器和链接器变得更快。

编译时间应该比 Go 1.7 改进了大约 15%

  • 对垃圾回收器改进,使两次垃圾回收的暂停时间减小到了毫秒级

同时识别了剩余仍未解决的暂停模式,并在下一个版本中得到修复。修复后,通常情况下暂停时间能控制在 100 微秒左右,甚至能低至 10 微秒。

  • 改进了 defer 函数

  • 部分标准库使用context包来改造

Go 1.7中进入标准库的context,提供了取消和超时机制。

Go 1.8 让标准库中更多package使用(支持)context,包括 database/sql,net 包, net/http 包中的 Server.Shutdown等

  • sort 包中新添加的 Slice 函数,对切片进行排序变得比之前简单得多

例如,对一个结构体类型的切片,使用结构体的一个字段来进行排序:

sort.Slice(s, func(i, j int) bool {  return s[i].Name < s[j].Name })


Go 1.8 Release Notes[46]





Go 1.9[47] - 2017 年 8 月:



  • 提升了垃圾收集器和编译器

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.

GC性能进一步提升,这要归功于一些库函数会触发并发垃圾收集机制,这样的话只会阻塞调用协程(goroutine),而不会阻塞整个程序。另外,大对象的堆内存分配也得到了明显提升。

Go 1.9 编译器能够并行编译同一个包中的函数。在之前版本的编译器中,已经支持了并行编译不同包中的函数。

  • 增加了类型别名

支持通过声明类型别名(type alias)实现渐进式代码重构[48](gradual code repair)


渐进式代码修复是代码重构中一种很有用的方式,对于大型的代码库来说很有价值。简而言之,渐进式代码修复的目标是通过一系列的步骤完成一个较大规模的重构,也就是说不会在一次自动化的提交中完成所有的变更,而是分成多次提交。原子性的重构方式在概念上通常很简单,但是如果代码库很大的话,就会造成规模很大的代码提交,这样很难审查和合并。借助渐进式代码修复,我们可以按照三个步骤来重构代码:首先,引入新的API,它应该能与旧的API 共存,所以我们不必立即修改所有使用旧API 的代码;然后,我们将使用旧API 的所有地方替换为新API;最后,将旧的API 移除。

为了启用渐进式代码修复,必须能为常量、函数、变量和类型创建另外一个备选的名称。现在,Go 允许通过如下的方式声明类型别名:

type OldAPI = NewPackage.API

这样的话,所有引用OldAPI的地方都会使用重构之后的类型

—详见Russ Cox Codebase Refactoring (with help from Go)[49]

  • 新增了sync.Map

提供了线程安全的并发map,具有恒定分摊时间(amortized-constant-time)的加载、存储和删除功能

其诞生是GopherCon 2017 - Lightning Talk: Bryan C Mills - An overview of sync.Map[50]得到灵感的

  • time包更加安全

Go 1.9 借助单调时间跟踪(monotonic time tracking),让time包的使用变得更加安全。即便是存在挂钟时间调整(wall clock adjustment),Time的对比也会更加容易。

(可以透明地跟踪每个时间值的 monotonic time,使两个时间之间的差值计算不受墙上时钟[51]调整的影响)

  • testing包新增helper方法

新的 Helper 方法,添加到 testing.T 和 testing.B 中,将调用函数标记为测试助手函数。当测试包打印文件和行信息时,它会显示对辅助函数的调用位置,而不是辅助函数本身中的一行。

go1.9_test.go:


1
2
3
4
5
6
7
8
9
10
11
12
package user

import "testing"

func failure(t *testing.T) {
t.Helper() // This call silences this function in error reports.
t.Fatal("failure")
}

func Test(t *testing.T) {
failure(t)
}


因为 failure 将自己标识为测试助手,所以在 Test 期间打印的错误消息将指示第 11 行调用失败的位置,而不是第 7 行调用失败调用 t.Fatal 的位置。


Go语言10年版本演进 (2012.03--2022.03)


Go 1.9 引入了类型别名并提升了运行时和工具支持[52]

Go 1.9发布 支持渐进式代码重构[53]


Go 1.9 Release Notes[54]








Go 1.10[55] - 2018 年 2 月:


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。



1
2
3
4
5
first run:
ok /go/src/retro 0.027s

second run:
ok /go/src/retro (cached)



  • go build 命令会缓存最近构建过的包,从而加快了构建过程

Go语言具有较高的编译性能是Go语言最初设计时就确定下来的目标,Go编译器的性能在Go 1.4.3版本达到顶峰,这虽然是得益于其使用C语言实现,但更重要的是其为高性能构建而定义的便于依赖分析的语言构建模型,同时避免了像C/C++那样的重复多次扫描大量头文件的负担。随着Go自举的实现,使用Go语言实现的go compiler性能有较大下降,但即便这样,其编译速度在主流编程语言中仍然是数一数二的。在经过了Go 1.6到Go1.9等多个版本对compiler的优化后,go compiler的编译速度已经恢复到Go 1.4.3 compiler的2/3左右或是更为接近的水平。在Go 1.9版本引入并行编译后,Go team在提升工具性能方面的思路发生了些许变化:不再是一味地进行代码级的性能优化,而是选择通过Cache,重复利用中间结果,实现增量构建,来减少编译构建所用的时间

Go 1.10中值得关注的几个变化[56]


Go 1.10 Release Notes[57]




Go 1.11[58] - 2018 年 8 月:




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.

此版本增加了对名为“模块”的新概念的初步支持,它是 GOPATH 的替代方案,具有对版本控制和包分发的集成支持。


Using Go Modules[60]


  • 增加了实验性的WebAssembly支持

这允许程序员将 Go 程序编译为与四种主要 Web 浏览器兼容的二进制格式


Go 1.11 Release Notes[61]






Go 1.12[62] - 2019 年 2 月:



  • 改进了Go modules

准备成为 Go 1.13 中的默认设置

  • 在analysis包[63]基础上重写了 go vet 命令

这个包有着更大的灵活性,允许开发人员编写自己的代码检查工具。

go vet 命令已被重写,可作为一系列不同源代码分析工具的基础。

一个副作用是不再支持 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.


根据重叠接口提案[68],Go 1.14 现在允许嵌入具有重叠方法集的接口:来自嵌入式接口的方法可能与(嵌入)接口中已经存在的方法具有相同的名称和相同的签名。这解决了菱形嵌入图通常(但不是唯一)出现的问题。像以前一样,接口中显式声明的方法必须保持唯一。



Diamond interface composition in Go 1.14[69]

  • 改进了defer的性能

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.


Goroutines 现在是异步可抢占的。因此,没有函数调用的循环不再可能使调度程序死锁或显着延迟垃圾收集。这在除 windows/arm、darwin/arm、js/wasm 和 plan9/
 之外的所有平台上都受支持。

实施抢占的结果是,在包括 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.

页面分配器效率更高,并且在 GOMAXPROCS 值较高时会显着减少锁争用。这是最明显的,因为并行和高速完成的大型分配具有更低的延迟和更高的吞吐量。



  • 内部定时器更高效


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.


time.After、time.Tick、net.Conn.SetDeadline 等使用的内部计时器效率将会更高,锁争用更少,上下文切换更少。这是一项性能改进,不会导致任何用户可见的更改。



Go 1.14 Release Notes[70]





Go 1.15[71] - 2020 年 8 月:



  • 一些优化,如改进了对高核心数的小对象的分配


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)

这个数据库Linux系统一般都有,是windows系统都没带。

没有 tzdata 就会从$GOROOT/中找。对于没有安装go环境的windows系统来说,就没办法通过 LoadLocation 设置时区。


在Go 1.15现在之前解决这个问题的办法,是自己把tzdata文件放到程序目录中,保证 time包能够从目录中加载到时区文件

go设置时区[72]

  • X.509 CommonName 弃用

  • GOPROXY 支持跳过返回错误的代理

  • 基本每个版本都有的一些库改进

如 sql库支持 DB.SetConnMaxIdleTimetime.Ticker 支持 Reset;strconv库增加了FormatComplexParseComplex用来处理复数



Go 1.15 Release Notes[73]







Go 1.16[74] - 2021 年 2 月:


  • GO111MODULE 默认为 on

根据 2020 年 Go 开发者调查,96% 的 Go 开发者已经改用Modules

  • //go:embed

可以在编译阶段将静态资源文件打包进编译好的程序中,并提供访问这些文件的能力

Go 1.16新特性-embed包及其使用[75]

  • 对macOS ARM64的支持

  • Linux 上释放内存改回用Go 1.12之前的 MADV_DONTNEED

之前为了使监控不告警,都需要指定 GODEBUG=madvdontneed=1



 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

  • 编译器带来了额外的改进

即一种传递函数参数和结果的新方法,程序性能提高了约 5%,amd64 平台的二进制大小减少了约 2%。

  • unsafe包新增了unsafe.Addunsafe.Slice

  • 一些包的改变

如net包:

URL 参数解析对 ; 支持的变化,原先 example?a=1;b=2&c=3 会解析成 map[a:[1] b:[2] c:[3]], 现在解析成map[c:[3]]

Go 1.17 Release Notes[79]





Go 1.18[80] - 2022 年 3 月:



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 工作区模式解决了这个问题,使用多个模块将变得简单。

倘若在工作目录或父目录中有go.work文件,或使用GOWORK环境变量进行指定,将使go命令进入工作区模式。
在此模式下,go.work文件将被用来确定作为模块解析根的一组主模块,而不是使用通常找到的go.mod文件来指定单一的主模块。


  • 20%的性能提升

Go 1.18将为ARM64架构带来高达 20% 的 CPU 性能改进

不过因为编译器中与支持泛型有关的变化,Go 1.18 的编译速度可能比Go 1.17的编译速度大约慢15%(编译后的代码的执行时间不受影响)。Go团队打算在Go 1.19中改进这次编译速度的降低。


Go 1.18 Release Notes[86]



参考资料

[1]文章: https://go.dev/blog/go1                                   

[2] 文章: https://go.dev/doc/go1compat

[3]文章:https://github.com/gperftools/gperftools

[4]文章:https://go.dev/doc/go1

[5]文章:https://go.dev/blog/go1.1

[6]文章:

https://dave.cheney.net/2013/05/21/go-11-performance-improvements

[7]文章:https://rakyll.org/scheduler/

[8]文章:https://go.dev/doc/go1.1#return

[9]文章:https://go.dev/doc/articles/race_detector

[10]文章:

https://medium.com/a-journey-with-go/go-race-detector-with-threadsanitizer-8e497f9e42db

[11]文章:https://go.dev/doc/go1.1

[12]文章:https://go.dev/blog/go1.2

[13]文章:https://go.dev/doc/go1.2#three_index

[14]文章:

https://docs.google.com/document/d/1GKKdiGYAghXRxC2BFrSEbHBZZgAGKQ-yXK-hRKBo0Kk/pub

[15]文章:https://go.dev/blog/cover

[16]文章:https://go.dev/doc/go1.2

[17]文章:https://go.dev/blog/go1.3

[18]文章:https://docs.google.com/document/d/1wAaf1rYoM4S4gtnPh0zOlGzWtrZFQ5suE8qr2sD8uWQ/pub

[19]文章:

https://medium.com/a-journey-with-go/go-how-does-the-goroutine-stack-size-evolve-447fc02085e5

[20]文章:https://studygolang.com/articles/28971

[21]文章:https://medium.com/a-journey-with-go/go-understand-the-design-of-sync-pool-2dde3024e277

[22]文章:https://studygolang.com/articles/21554

[23]文章:https://docs.google.com/document/d/1yIAYmbvL3JxOKOjuCyon7JhW4cSv1wy5hC0ApeGMV9s/pub

[24]文章:https://go.dev/doc/go1.3

[25]文章:https://go.dev/blog/go1.4

[26]文章:https://go.dev/blog/generate

[27]文章:

https://docs.google.com/document/d/1e8kOo3r51b2BWtTs_1uADIA5djfXhPT36s6eHVRIvaU/edit

[28]文章:https://go.dev/doc/go1.4

[29]文章:https://go.dev/blog/go1.5

[30]文章:

https://docs.google.com/document/d/106hMEZj58L9nq9N9p7Zll_WKfo-oyZHFyI6MttuZmBU/edit#

[31]文章:https://github.com/golang/go/wiki/Go-Release-Cycle

[32]文章:https://go.dev/doc/go1.5#gc

[33]文章:

https://docs.google.com/document/d/1wmjrocXIWTr1JxU-3EQBI6BK6KgtiFArkG47XK73xIQ/edit#

[34]文章:https://go.dev/talks/2015/go-gc.pdf

[35]文章:https://docs.google.com/document/d/1yIAYmbvL3JxOKOjuCyon7JhW4cSv1wy5hC0ApeGMV9s/pub

[36]文章:

https://docs.google.com/document/d/1At2Ls5_fhJQ59kDK2DFVhFu3g5mATSXqqV5QrxinasI/edit

[37]文章:

https://docs.google.com/document/d/1FP5apqzBgr7ahCCgFO-yoVhk4YZrNIDNf9RybngBc14/pub

[38]文章:https://go.dev/doc/go1.5

[39]文章:https://go.dev/blog/go1.6

[40]文章:https://pkg.go.dev/runtime#hdr-Environment_Variables

[41]文章:https://go.dev/doc/go1.6

[42]文章:https://go.dev/blog/go1.7

[43]文章:https://go.dev/blog/context

[44]文章:https://go.dev/doc/go1.7

[45]文章:https://go.dev/blog/go1.8

[46]文章:https://go.dev/doc/go1.8

[47]文章:https://go.dev/blog/go1.9

[48]文章:https://www.cnblogs.com/majianguo/p/6792189.html

[49]文章:https://talks.golang.org/2016/refactor.article

[50]文章:https://www.youtube.com/watch?v=C1EtfDnsdDs

[51]文章:https://www.cnblogs.com/fortunely/p/14779041.html

[52]文章:https://www.infoq.cn/article/2017/09/golang-19-released

[53]文章:https://blog.csdn.net/qiansg123/article/details/80131217

[54]文章:https://go.dev/doc/go1.9

[58]文章:https://go.dev/blog/go1.11

[59]文章:https://tonybai.com/2018/02/17/some-changes-in-go-1-10/

[60]文章:https://go.dev/blog/using-go-modules

[61]文章:https://go.dev/doc/go1.11

[62]文章:https://go.dev/blog/go1.12

[63]文章:https://pkg.go.dev/golang.org/x/tools/go/analysis

[64]文章:https://go.dev/doc/go1.12

[65]文章:https://go.dev/blog/go1.13

[66]文章:https://go.dev/doc/go1.13

[67]文章:https://go.dev/blog/go1.14

[68]文章:https://github.com/golang/proposal/blob/master/design/6977-overlapping-interfaces.md

[69文章:

https://dave.cheney.net/2020/05/24/diamond-interface-composition-in-go-1-14

[70]文章:https://go.dev/doc/go1.14

[71]文章:https://go.dev/blog/go1.15

[72]文章:https://studygolang.com/articles/13027

[73]文章:https://go.dev/doc/go1.15

[74]文章:https://go.dev/blog/go1.16

[75]文章:https://zhuanlan.zhihu.com/p/351931501

[76文章:

https://dashen.tech/2021/03/26/Go-1-12-%E5%85%B3%E4%BA%8E%E5%86%85%E5%AD%98%E9%87%8A%E6%94%BE%E7%9A%84%E4%B8%80%E4%B8%AA%E6%94%B9%E8%BF%9B/

[77]文章:https://go.dev/doc/go1.16

[78]文章:https://go.dev/blog/go1.17

[79]文章:https://go.dev/doc/go1.17

[80]文章:https://go.dev/blog/go1.18

[81]文章:https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md

[82文章:https://research.swtch.com/generic

[83]文章:https://github.com/golang/go/issues/48918

[84]文章:https://go.dev/doc/fuzz/

[85]文章:https://github.com/golang/go/issues/44551

[86]文章:https://go.dev/doc/go1.18

更多参考:

https://go.dev/blog/all

https://golang.design/history/cn.html

https://www.infoq.cn/article/kx69fgexcjeeczz6crie