Go 版本改动(个人理解)记录

2年前 (2022) 程序员胖胖胖虎阿
174 0 0

重要说明:

  • 本文仅记录了个人阅读 go release notes 之后的一些肤浅理解,一定会存在大量的错误。
  • 有很多重要的改动没有被列出(可能是因为本人无法理解或者不感兴趣)。
  • 切记不要当做 Go release notes 的中文翻译,仅仅是一个小笔记。具体的内容请一定请参考原文说明。

官方 Release Notes:
https://go.dev/doc/go1.x (替换 url 最后的版本号即可)

由于本人是从 Go 1.3/1.4 阶段开始接触 Go 的,因此1.5之前的一些修改就不关注了。

Go 1.5

  • GC 改动(消除 stw)。
  • 调度器改动(并发度更高)。
  • Bootstrapping、移出 C 代码,编译器工具链用 Go(大部分由 C转化而来);移出 6a/6l/6g 等。
  • (负面)编译器的速度极大的变慢。
  • 在 x86 上面的动态链接特性。

Go 1.6

  • 加入了 race detector。
  • 编译器前端解析器手写(不使用 yacc)。
  • vendoring;挂掉的时候打出所有 routine 堆栈;GC 优化。

Go 1.7

  • 编译器后端优化 SSA(针对 64-bit x86),性能提升。
  • Toolchain 优化:新的导出格式;编译器和链接器性能提升;更小的二进制输出;

Go 1.8

  • Assembler 加入某些 64-bit 机器的新指令。
  • 去除 yacc 相关的内容。
  • SSA 使用到全部的支持架构上。
  • 新的 compiler 前端,用户无感知但是丢后续性能优化非常重要。
  • 优化 compiler 和 linker 性能。
  • Plugin 的初步支持。
  • 优化了 GC 和 defer,以及一些标准库。

Go 1.9

  • Package 内并发编译。
  • Compiler 和 linker DWARF 信息相关改动。
  • ARM assembler MULA 指令 bug fix。
  • 工具 pprof 不需要二进制代码就能够查看各种符号(代码行等)信息;pprof.Do;pprof.Label 更新。
  • GC only blocks the calling routine.
  • 新的 bits 标准库;sync.Map 标准库;

Go 1.10

  • Build 时候只按照代码来推断是否需要重新编译(而不是修改时间或者 metadata/build flags)。所以不需要 -a 的编译参数了。
  • 和第一条类似,go test 也会正确的 cache 结果。go vet 集成到 go test 调用中。
  • 在 pprof 中 blocking 和 mutex 的 profile 文件也自带符号表了。
  • Assembler 支持更多的指令(在不同的平台)。

Go 1.11 改动:

  • Go mods 首次加入。
  • Build 时 cache 默认开启;一些内联函数优化;新引入的包导出格式;switch 的未使用变量检查;
  • 链接器支持 AVX512;DEBUG信息优化;默认压缩的DWARF 信息;memprof默认使用 alloc 的 profile;vet 优化;
  • Runtime: a sparse heap layout.
  • Map 遍历删除和 slice extension 优化。
  • 编译器优化:bounds-check and branch elimination, transitive relations;各种看不懂的优化。

Go 1.12

  • 后续不支持 binary library.
  • Go doc 和 go vet 替代 godoc 和 go tool vet。
  • GC 和内存管理相关的优化。

Go 1.13

  • 数字表达方式更改。
  • go module 默认行为改变;GOPRIVATE环境变量;go get 行为改变;二进制中包含模块版本信息;
  • 逃逸分析改进(重写);
  • 修改 Error wrapper 写法.
  • 默认使用 MADV_FREE 来向 os 释放内存(会导致 RSS 变高)。

Go 1.14

  • overlapping interfaces proposal 嵌入 struct 的重名机制。
  • 提升 defer 性能到几乎0开销(和直接调用该函数相比)。
  • 主流平台上实现 goroutin 的异步抢占?(asynchronously preemptible);系统调用的时候会增加很多 EINTR 需要自己处理。
  • CPU 数量很多的情况下,大块内存并行高频分配时候的减少锁竞争优化。
  • 各种 timer, tick, wait 的优化,减少锁和上下文切换开销。
  • 增加一个 bytes 的 hash 函数。

Go 1.12 - Go 1.14

Go 1.15

  • Panic 涉及到的变量如果是基础类型派生的,那么把值打出来。
  • SIGSEGV, SIGBUS, SIGFPE 会杀掉进程(如果不显式处理的话)。
  • 小对象分配优化(在 cpu core 很多的场景下);small int to interface 优化;已关闭的阻塞/非阻塞 chan 行为统一。
  • 生成的 bin 文件比上个版本小 5%(消除一些 GC 和未使用类型的 metadata);
  • unsafe.Pointer 和 uintptr 的转换规则修改;在编译参数中加入缓解 Spectre漏洞影响的选项。
  • 链接器大优化(效率和内存使用),是通过新设计的 obj 文件格式和并发某些操作阶段的并发执行带来的。

Go 1.16

  • 支持 Apple Silicon。
  • 默认使用 go.mod,带来 go install/go get 等一堆工具的用法修改。
  • 可以使用 //go:embed 来嵌入各种文件。
  • 用于取代 runtime.ReadMemStatsdebug.GCStats 等运行时接口的 runtime/metrics;Debug 参数 inittrace=1 检查启动效率;
  • 内存释放策略又改成了 MADV_DONTNEED(在之前的 1.13 版本变更为 MADV_FREE)。
  • (接上个版本的)链接器后续优化。
  • 文件处理和 io 相关的一些修改,集中在 io/fs

Go 1.17

  • []T 可以直接转换为 [N]T了。还有一堆新的 unsafe 指针运算。

    l := []int{1, 2, 3, 4, 5, 6, 7}
    al := *(*[5]int)(unsafe.Pointer(&l)) // 错误用法!
    al2 := *(*[5]int)(unsafe.Pointer(&l[0])) // [1 2 3 4 5]
    al3 := (*[5]int)(l) // &[1 2 3 4 5]
  • 新的Module graph pruning
    这个特征应该叫做依赖关系图修剪?我的理解是:
    依赖的库中,跟你的项目(main module)无关的那些依赖内容,会在 go.mod 中标记为 // indirect,而其他的依赖,被称为 require directive。但是为什么要做么做,没有看明白
  • 一堆 go mod 相关的行为变化。
  • 一种新的函数调用传参方式(使用寄存代替栈),提高5%的性能,较少2%的执行文件容量。应用在 linux/amd64 等最主流体系上。

Go 1.18

  • 试验性质的泛型支持。(能力有限,c++中的泛型也没搞明白,无法描述)
  • 修复掉长期未处理的一个bug #8560 (一个特殊场景的声明变量未使用,未被探测到的问题)。
  • Fuzzing 支持(貌似是和测试相关的)。
  • 一堆 go mod 相关行为变化。
  • go workspace 的引入,看起来像是一个IDE 的工程文件。
  • gofmt 工具并发。
  • go vet 能够更智能的检测到一些代码写法的问题。
  • GC 在评估执行频率的时候考虑了不在堆上的资源(例如栈扫描)。
  • slice 扩容算法变更(避免突变?)。
  • 1.17版本的传参优化应用到大部分平台上。这个优化带来的,可能影响堆栈打印不准确的问题,在1.18中会标记一个 ? 符号。
  • 编译速度慢 15%,生成代码的执行速度不变。
  • Bootstrapping 的时候,优先使用 Go 1.17(之前是 1.4),而且预告了在 Go 1.19 的时候,需要用 Go 1.17。(这里不得不吐槽一下:说好的都用 Go 1.4 bootstrapping 呢?)

Go 1.19

  • 最大的修改:内存模型修改(没看懂)。
  • 优化了 go doc 输出文档的格式。如果按照规范书写,go doc 可以输出超链接和列表格式的文档。
  • unix build constraint(类似宏)
  • 一堆工具小修改:build 参数加入(在 -trimpath的情况下)、go generate、go env FLAG quotes、go list 输出优化和 cache。
  • 加了一个 soft memory limit,查了一下其他的人的说法,看起来是为了避免发生 OOM。
  • 超大的 int/string switch 情况下使用 jump table 优化。
版权声明:程序员胖胖胖虎阿 发表于 2022年10月6日 上午5:16。
转载请注明:Go 版本改动(个人理解)记录 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...