Go 1.10 Release Notes 要点整理

Go 1.10,在Go 1.9发布半年后如期而至。其主要变化在工具链实现、运行时及库上面。一如既往,该版本秉承Go 1兼容性准则。以期所有的Go程序如之前一样编译及运行。

该版本改进了包构建缓存,增加了成功测试结果缓存,在测试时自动进行校验,且准许使用cgo在Go及C程序间直接传递string类型的值。

1 语言方面

语言基准未有大的变化。

阐明了未指定类型的常量移位,编译器已允许诸如x[1.0 « s](s是一个无符号整型变量)的索引表达式。

method expression语法已放宽到允许任何类型表达式作为接收器;如struct{io.Reader}.Read是有效的。

2 工具方面

  • 默认GOROOT及GOTMPDIR 若未设置$GOROOT,之前go tool会在工具链编译时使用默认的GOROOT设置。现在,在使用默认设置之前,go tool会从其自己的执行路径推断GOROOT。这样,即允许二进制文件解压到文件系统的任意位置,且可在未显式设置GOROOT的情况下使用。

默认情况下,go tool会在系统临时文件夹下创建文件夹及文件(如Unix的$TMPDIR),若设置了新的变量$GOTMPDIR,即会改为在该文件夹下创建。

  • Build & Install go build命令目前可以基于源文件内容与构建标记及存储在编译包上的元数据来检测出过期的包。修改时间不再会考量。当修改时间产生误导的时候,之前增加-a标记以强制构建的建议已没有必要:构建目前总会检查包何时需要重新构建。

go build的-asmflags、-gcflags、-gccgoflags、及-ldflags选项目前默认仅应用于命令行直接列出的包。例如,go build -gcflags=-m mypkg会在对mypkg包而非其依赖构建时给编译器传入-m标记。新的更通用的方式-asmflags=pattern=flags仅会将标记应用到匹配了模式的包。例如:go install -ldflags=cmd/gofmt=-X=main.version=1.2.3 cmd/...会对满足cmd/...的包安装所有命令,但仅会对cmd/gofmt应用-X选项。更多详情请参阅go help build

go build命令目前维护了一块最近构建包的缓存(不同于包安装路径$GOROOT/pkg或$GOPATH/pkg)。缓存应会对未显式安装包或当在源码的不同副本中切换时(如在同一版本控制系统的不同分支上前后切换)起到加速构建的作用。之前添加-i标记以加速(诸如go build -igo test -i)的建议已没有必要:有没有-i都会一样快,更多详情请参阅go help cache

go install命令目前仅安装直接在命令行列出的包与命令。例如go install cmd/gofmt安装了gofmt程序,但没有安装其任何依赖。新的构建缓存使得未来的命令仍可运行的好似安装了依赖一样快。使用新的go install -i标记可以强制安装依赖。

go build的诸多实现细节已对这些改进作了支持。一个新的改变是纯二进制包的引用必须在其被引用源码中声明准确的引用块。这样,当使用纯二进制包链接一个程序的时候以让这些引用是可用的。更多详情请查阅go help filetype

  • Test go test目前缓存了测试结果:若test可执行且命令行匹配了之前的一次执行,且检测到文件及环境变量未发生改变,那么go test将会打印之前的测试结果(时间耗费字段将会被替换为字符串“(cached)”)。Test缓存仅应用于成功的测试结果;仅应用在显式列出包的go test命令;仅应用在使用-cpu、-list、-parallel、-run、-short及-v的测试标记子集的命令行。理想的略过测试缓存的方式是使用-count=1。

go test命令目前会对将要测试的包自动运行go vet,以在运行测试前识别重要问题。此类问题会造成构建错误及阻止测试执行。使用go test -vet=off可以关闭该检测。

go test -coverpkg标记目前将其参数解释为一个按冒号分割的模式列表以匹配每个测试的依赖,并非作为一个包列表以重新加载。如go test -coverpkg=all目前是一个对测试包及其所有依赖开启覆盖率测试的有趣方式。同样,go test -coverprofile选项目前也支持运行多组测试。

对于超时的错误情形,测试更可能在退出前写入画像。

go test目前会从给定的二进制执行中将标准错误并入标准输出然后写到go test的标准输出中。而之前go test仅会在多数时间应用该合并。

目前,当并行测试停顿或继续的时候,go test -v输出会包括PAUSE及CONT状态标记行。

新的go test -failfast标记在测试失败时将不会运行剩余的测试。(注:以并行方式运行的测试在测试运行失败时允许测试执行完成)

最后,新的go test -json标记通过新的go tool test2json命令过滤测试输出以生成机器可读的JSON格式的测试执行描述。这样会允许在IDE及其它工具中创建更多丰富的说明信息。

更多详情请参阅go help testtest2json文档

  • Doc go doc工具目前增加了对于类型T的[]T或[]T等slice结果返回函数的显示(类似于现有的对单个T或T返回函数的显示机制)。例如:
$ go doc mail.Address

type Address struct {
	Name    string // Proper name; may be empty.
	Address string // user@domain
}
    Address represents a single mail address. An address such as "Barry Gibbs
    " is represented as Address{Name: "Barry Gibbs", Address:
    "bg@example.com"}.

func ParseAddress(address string) (*Address, error)
func ParseAddressList(list string) ([]*Address, error)
func (a *Address) String() string

之前ParseAddressList函数仅会在包预览时显示(go doc mail)。

  • Pprof 通过runtime/pprof包生成的阻塞及互斥的画像目前包含了符号信息,这些符号信息可以在没有产生画像的二进制中使用go tool pprof查看。(所有其它画像类型已在Go 1.9更新为包含符号信息)

go tool pprof画像可视化工具已更新至git版本9e20b5b(github.com/google/pprof),该版本包含一个更新了的web接口。

  • Vet go vet命令目前在检查包(甚至对使用cgo或vendored方式引入的包)的时候总是使用完整的最新的类型信息。结果报告应该会更准确一些。注意仅go vet有权访问这些信息,应避免使用go tool vet。(截至Go 1.9,go vet已提供类似go tool vet所有标记的访问)

  • Gofmt Go源码的默认格式化有两处小的细节上的改动。第一个,对于三索引slice表达式之前会被格式化为x[i+1 : j:k],而目前会被使用定长空格格式化为x[i+1 : j : k]。第二个,写作单行的单个方法接口(有时会在类型断言时使用)将不再格式化为多行。

注意这类针对gfmt的小的更新将会不定期进行。一般讲,检查源码的构建系统应匹配指定版本的gofmt的输出。

  • 编译器工具链 编译器对代码生成的性能上作了诸多改进(在所支持的体系结构上广泛着手)。

记录于二进制的DWARF调试信息有几项改进:常量值目前会被记录;行号信息会更精确,使得源码级调试更好一些;并且目前每个包会呈现其自己的DWARF编译单元。

各种构建模式已移植到更多的系统。特别是c-shared目前工作在linux/ppc64le、windows/386,及windows/amd64上;pie目前工作在darwin/amd64,且同样在所有系统上强制使用外部链接;plugin目前工作在linux/ppc64le及darwin/amd64上。

linux/ppc64le端目前需要对使用cgo的任何程序(甚至被标准库使用时)使用外部链接。

3 运行时

嵌套调用LockOSThread及UnlockOSThread的行为已发生改变。这些函数用来控制是否一个goroutine被锁定在一个操作系统线程上,以让该goroutine仅在那个线程上运行,且那个线程仅运行该goroutine。之前在一行调用LockOSThread多次相当于调用一次,而仅调用一次UnlockOSThread即可解锁线程。现在调用是嵌套的:调用LockOSThread多次,须调用UnlockOSThread同样次数才能解锁。没有嵌套调用的现有代码仍可正确运行。多数使用这些函数的公开Go源码被分入了第二类。

因通常使用LockOSThread与UnlockOSThread来允许Go源码可靠的修改本地线程状态(如Linux或Plan 9命名空间)。运行时目前认为被锁的线程不适于重用或用来创建新线程。 除非包装器自己出现了错误,堆栈信息不再包含隐式的包装函数(之前被标记为)。 结果,传给诸如Caller函数的跳过次数目前应匹配所写代码的结构,而非依赖优化决策及实现细节。 垃圾收集器已减少对分配延迟的影响。当运行时,其目前使用更少部分的总体CPU,但可能会运行更长的时间。被垃圾收集器使用的总体CPU没有发生显著改变。

GOROOT函数目前实际上是在调用程序编译后,默认使用GOROOT或GOROOT_FINAL。而之前,是在编译调用程序的工具链编译后,使用GOROOT或GOROOT_FINAL。

GOMAXPROCS设置目前已无上限。(在Go 1.9,上限为1024)

4 性能

一如既往,该版本变化较广,较难对性能作精确陈述。因垃圾收集器加速、更好的代码生成及核心库的优化,多数程序应会运行的快一些。

5 垃圾收集器

当垃圾收集器活跃时,多数程序应会感受到更低的分配延迟及总体的性能提升。

6 核心库

标准库的所有改动都比较小,bytes包及net/url包的变化可能需要更新现有的程序。

参考资料

[1] https://golang.org/doc/go1.10