Go 1.9 版本说明

Go 1.9 简介

最新的 Go 版本 1.9 在 Go 1.8 发布六个月后发布,是 Go 1.x 系列 的第十个版本。有两个 语言更改:添加对类型别名的支持,以及定义实现何时可以融合浮点运算。大多数更改是在工具链、运行时和库的实现中进行的。与往常一样,此版本维护了 Go 1 的 兼容性承诺。我们预计几乎所有 Go 程序都将继续像以前一样编译和运行。

此版本添加了 透明单调时间支持并行编译包中的函数、更好地支持 测试辅助函数,并包含一个新的 位操作包 以及新的 并发映射类型

语言更改

有两个语言更改。

Go 现在支持类型别名,以便在将类型从一个包移动到另一个包时支持逐步代码修复。 类型别名设计文档一篇关于重构的文章 详细介绍了这个问题。简而言之,类型别名声明的形式为

type T1 = T2

此声明引入了别名 T1T2 的另一种写法)来表示 T2 所表示的类型;也就是说,T1T2 表示相同的类型。

另一个较小的语言更改是, 语言规范现在说明 实现何时可以将浮点运算融合在一起,例如使用架构的“融合乘加”(FMA) 指令计算 x*y + z,而无需对中间结果 x*y 进行舍入。若要强制执行中间舍入,请编写 float64(x*y) + z

移植

此版本中没有新的受支持操作系统或处理器架构。

ppc64x 需要 POWER8

GOARCH=ppc64GOARCH=ppc64le 现在都需要至少支持 POWER8。在之前的版本中,只有 GOARCH=ppc64le 需要 POWER8,而大端 ppc64 架构支持较旧的硬件。

FreeBSD

Go 1.9 是将在 FreeBSD 9.3 上运行的最后一个版本,该版本已被 FreeBSD 不再支持。Go 1.10 将需要 FreeBSD 10.3+。

OpenBSD 6.0

Go 1.9 现在为 cgo 二进制文件启用 PT_TLS 生成,因此需要 OpenBSD 6.0 或更高版本。Go 1.9 不再支持 OpenBSD 5.9。

已知问题

FreeBSD 上存在一些已知但尚不清楚的不稳定性。在极少数情况下,这些情况会导致程序崩溃。请参阅 问题 15658。任何帮助解决此 FreeBSD 特定问题都将不胜感激。

在 Go 1.9 开发周期中,Go 停止运行 NetBSD 构建器,因为 NetBSD 内核崩溃,一直到 NetBSD 7.1。随着 Go 1.9 的发布,NetBSD 7.1.1 也发布了修复程序。但是,目前我们没有 NetBSD 构建器通过我们的测试套件。任何帮助调查 各种 NetBSD 问题 都将不胜感激。

工具

并行编译

Go 编译器现在支持并行编译包中的函数,以利用多个内核。这与 go 命令对单独包的并行编译的现有支持相补充。并行编译默认启用,但可以通过将环境变量 GO19CONCURRENTCOMPILATION 设置为 0 来禁用。

使用 ./… 进行供应商匹配

根据普遍需求,./... 不再匹配接受包名称的工具(例如 go test)中的 vendor 目录中的包。要匹配供应商目录,请编写 ./vendor/...

移动 GOROOT

go 工具 现在将使用其调用的路径来尝试定位 Go 安装树的根目录。这意味着如果将整个 Go 安装程序移动到新的位置,go 工具应继续照常工作。这可以通过在环境中设置 GOROOT 来覆盖,这仅应在特殊情况下执行。请注意,这不会影响 runtime.GOROOT 函数的结果,该函数将继续报告原始安装位置;这可能会在以后的版本中修复。

编译器工具链

复杂除法现在与 C99 兼容。在 gccgo 中一直都是这种情况,现在在 gc 工具链中已修复。

链接器现在将为 Windows 上的 cgo 可执行文件生成 DWARF 信息。

如果提供 -N -l 标志,编译器现在将在生成的 DWARF 中包含词法范围,使调试器能够隐藏不在范围内的变量。.debug_info 部分现在是 DWARF 版本 4。

GOARMGO386 的值现在会影响已编译包的构建 ID(由 go 工具的依赖项缓存使用)。

汇编器

四操作数 ARM MULA 指令现在已正确汇编,其中加数寄存器为第三个参数,结果寄存器为第四个也是最后一个参数。在之前的版本中,这两个含义颠倒了。三操作数形式(其中第四个参数隐式与第三个参数相同)不受影响。使用四操作数 MULA 指令的代码将需要更新,但我们认为这种形式很少使用。MULAWTMULAWB 在所有形式中都已使用正确的顺序,并且没有改变。

汇编器现在支持 ADDSUBPS/PD,完成了两个缺少的 x86 SSE3 指令。

文档

现在对长参数列表进行了截断。这提高了某些生成代码上 go doc 的可读性。

现在支持查看结构体字段的文档。例如,go doc http.Client.Jar

环境

新的 go env -json 标志启用 JSON 输出,而不是默认的操作系统特定输出格式。

测试

go test 命令接受一个新的 -list 标志,该标志以正则表达式作为参数,并将与之匹配的任何测试、基准测试或示例的名称打印到标准输出,而不会运行它们。

Pprof

runtime/pprof 包生成的配置文件现在包含符号信息,因此可以在 go tool pprof 中查看它们,而无需生成配置文件的二进制文件。

go tool pprof 命令现在使用环境中定义的 HTTP 代理信息,使用 http.ProxyFromEnvironment

Vet

vet 命令 已更好地集成到 go 工具 中,因此 go vet 现在支持所有标准构建标志,而 vet 自己的标志现在可以通过 go vetgo tool vet 获取。

Gccgo

由于 Go 的半年发布计划与 GCC 的年度发布计划对齐,因此 GCC 版本 7 包含 Go 1.8.3 版本的 gccgo。我们预计下一个版本 GCC 8 将包含 Go 1.10 版本的 gccgo。

运行时

包含内联帧的调用堆栈

runtime.Callers 的用户应避免直接检查结果的 PC 切片,而应使用 runtime.CallersFrames 获取调用堆栈的完整视图,或使用 runtime.Caller 获取有关单个调用者的信息。这是因为 PC 切片中的单个元素无法说明内联帧或调用堆栈的其他细微差别。

具体来说,直接遍历 PC 切片并使用诸如 runtime.FuncForPC 等函数来单独解析每个 PC 的代码将错过内联帧。若要获取堆栈的完整视图,此类代码应改为使用 CallersFrames。同样,代码也不应假设由 Callers 返回的长度是调用深度的任何指标。它应该改为计算由 CallersFrames 返回的帧数。

查询特定深度处的单个调用者的代码应使用 Caller,而不是将长度为 1 的切片传递给 Callers

runtime.CallersFrames 自 Go 1.7 起可用,因此可以在升级到 Go 1.9 之前更新代码。

性能

与往常一样,更改非常通用且变化无常,因此难以做出关于性能的精确陈述。由于垃圾回收器、生成的代码和核心库优化方面的加速,大多数程序应该运行得更快一些。

垃圾回收器

以前会触发停止世界垃圾回收的库函数现在会触发并发垃圾回收。具体来说, runtime.GCdebug.SetGCPercentdebug.FreeOSMemory 现在会触发并发垃圾回收,仅阻塞调用协程,直到垃圾回收完成。

debug.SetGCPercent 函数仅在由于新的 GOGC 值而立即需要垃圾回收时才会触发垃圾回收。这使得能够动态调整 GOGC。

在使用大型(>50GB)堆且包含大量大型对象的应用程序中,大型对象分配性能得到显著提升。

现在,即使对于非常大的堆,runtime.ReadMemStats 函数也只需不到 100 微秒。

标准库

透明单调时间支持

现在,time 包会透明地跟踪每个 Time 值的单调时间,这使得在存在时钟调整的情况下,计算两个 Time 值之间的时间跨度成为一项安全的操作。有关详细信息,请参阅 包文档设计文档

新的位操作包

Go 1.9 包含一个新包 math/bits,其中包含用于操作位的优化实现。在大多数架构上,编译器可以识别此包中的函数,并将其视为内联函数,以提高性能。

测试辅助函数

新的 (*T).Helper(*B).Helper 方法将调用函数标记为测试辅助函数。在打印文件和行信息时,该函数将被跳过。这允许编写测试辅助函数,同时仍然为用户提供有用的行号。

并发映射

sync 包中的新类型 Map 是一个并发映射,具有均摊常数时间负载、存储和删除操作。多个 goroutine 可以安全地并发调用 Map 的方法。

探查器标签

runtime/pprof 现在支持向 pprof 探查器记录添加标签。标签构成一个键值映射,用于在使用 pprof 命令 查看配置文件时,区分不同上下文中同一函数的调用。pprof 包的新函数 Do 函数 会运行与一些提供的标签相关联的代码。包中的其他新函数有助于处理标签。

库中的细微变化

与往常一样,对库进行了各种细微更改和更新,并牢记 Go 1 的 兼容性承诺

archive/zip

ZIP Writer 现在会在适当情况下在 FileHeader.Flags 中设置 UTF-8 位。

crypto/rand

在 Linux 上,Go 现在会调用 getrandom 系统调用,但不带 GRND_NONBLOCK 标志;现在它将阻塞,直到内核拥有足够的随机性。在早于 getrandom 系统调用的内核上,Go 将继续从 /dev/urandom 读取。

crypto/x509

在 Unix 系统上,现在可以使用环境变量 SSL_CERT_FILESSL_CERT_DIR 分别覆盖 SSL 证书文件和 SSL 证书文件目录的系统默认位置。

FreeBSD 文件 /usr/local/etc/ssl/cert.pem 现在已包含在证书搜索路径中。

该包现在支持名称约束中的排除域。除了执行此类约束之外,CreateCertificate 还会在提供的模板证书包含新的字段 ExcludedDNSDomains 时,创建具有排除名称约束的证书。

如果证书中存在任何 SAN 扩展(包括没有 DNS 名称的扩展),则会忽略来自 Subject 的通用名称。在之前的版本中,代码只测试证书中是否存在 DNS 名称 SAN。

database/sql

该包现在将在 Tx.Stmt 中使用可用的缓存 Stmt。这可以防止每次调用 Tx.Stmt 时重新准备语句。

该包现在允许驱动程序通过实现 driver.NamedValueChecker 来实现自己的参数检查器。这也允许驱动程序支持 OUTPUTINOUT 参数类型。Out 应在驱动程序支持的情况下用于返回输出参数。

Rows.Scan 现在可以扫描用户定义的字符串类型。以前,该包支持扫描到数值类型,例如 type Int int64。现在它还支持扫描到字符串类型,例如 type String string

新的 DB.Conn 方法返回新的 Conn 类型,该类型表示来自连接池的数据库的专有连接。在调用 Conn.Close 将连接返回连接池之前,在 Conn 上运行的所有查询都将使用相同的底层连接。

encoding/asn1

新的 NullBytesNullRawValue 表示 ASN.1 NULL 类型。

encoding/base32

新的 Encoding.WithPadding 方法添加了对自定义填充字符和禁用填充的支持。

encoding/csv

新字段 Reader.ReuseRecord 控制对 Read 的调用是否可以返回一个切片,该切片共享先前调用返回的切片的备用数组,以提高性能。

fmt

在打印浮点数和复数时,现在支持井号标志(’#’)。它将始终为 %e%E%f%F%g%G 打印一个小数点;它不会为 %g%G 删除尾随零。

hash/fnv

该包现在包括 128 位 FNV-1 和 FNV-1a 哈希支持,分别使用 New128New128a

html/template

如果在管道中找到预定义的转义器(“html”、“urlquery” 和 “js” 之一)并且与自动转义器自行决定的结果不匹配,则该包现在会报告错误。这避免了某些安全或正确性问题。现在,使用这些转义器之一始终是无操作或错误。(无操作情况简化了从 text/template 的迁移。)

image

Rectangle.Intersect 方法现在在对相邻但非重叠的矩形调用时会返回一个零 Rectangle,如文档中所述。在早期版本中,它会错误地返回一个空但非零 Rectangle

image/color

YCbCr 到 RGBA 的转换公式已进行调整,以确保舍入调整跨越完整的 [0, 0xffff] RGBA 范围。

image/png

新字段 Encoder.BufferPool 允许指定 EncoderBufferPool,编码器将使用该池在编码 PNG 图像时获取临时的 EncoderBuffer 缓冲区。使用 BufferPool 会减少在编码多个图像时执行的内存分配次数。

该包现在支持解码透明的 8 位灰度 (“Gray8”) 图像。

math/big

新的 IsInt64IsUint64 方法报告 Int 是否可以表示为 int64uint64 值。

mime/multipart

新字段 FileHeader.Size 描述了多部分消息中文件的大小。

net

新的 Resolver.StrictErrors 提供了对 Go 内置 DNS 解析器如何处理由多个子查询(例如 A+AAAA 地址查找)组成的查询期间的临时错误的控制。

新的 Resolver.Dial 允许 Resolver 使用自定义拨号函数。

JoinHostPort 现在只在主机包含冒号时将地址放在方括号中。在之前的版本中,如果地址包含百分号 (’%’) 符号,它也会将地址放在方括号中。

新的方法 TCPConn.SyscallConnIPConn.SyscallConnUDPConn.SyscallConnUnixConn.SyscallConn 提供了对连接的底层文件描述符的访问权限。

现在,可以使用从 (*TCPListener).String() 获得的地址安全地调用 Dial,前提是在使用 Listen(“tcp”, “:0”) 创建监听器之后。以前,它在某些具有半配置的 IPv6 堆栈的机器上失败。

net/http

Cookie.String 方法(用于 CookieSet-Cookie 标头)现在会在值包含空格或逗号时将值用双引号括起来。

服务器更改

客户端和传输更改

net/http/fcgi

新的 ProcessEnv 函数返回与 HTTP 请求关联的 FastCGI 环境变量,这些请求没有相应的 http.Request 字段,例如 REMOTE_USER

net/http/httptest

新的 Server.Client 方法返回一个 HTTP 客户端,该客户端配置为向测试服务器发出请求。

新的 Server.Certificate 方法返回测试服务器的 TLS 证书(如果有)。

net/http/httputil

ReverseProxy 现在会代理所有 HTTP/2 响应尾部,即使是那些未在初始响应标头中声明的尾部。此类未声明的尾部由 gRPC 协议使用。

os

os 包现在使用内部运行时轮询器进行文件 I/O。这减少了管道上读/写操作所需的线程数,并且消除了一个 goroutine 关闭文件而另一个 goroutine 使用文件进行 I/O 时发生的竞争条件。

在 Windows 上,现在在没有 shell32.dll 的情况下填充 Args,从而将进程启动时间缩短了 1-7 毫秒。

os/exec

os/exec 包现在阻止子进程创建具有任何重复环境变量。如果 Cmd.Env 包含重复的环境键,则只使用每个重复键的切片中的最后一个值。

os/user

LookupLookupId 现在在 CGO_ENABLED=0 时在 Unix 系统上工作,方法是读取 /etc/passwd 文件。

LookupGroupLookupGroupId 现在在 CGO_ENABLED=0 时在 Unix 系统上工作,方法是读取 /etc/group 文件。

reflect

新的 MakeMapWithSize 函数创建具有容量提示的映射。

runtime

运行时生成的并记录在配置文件中的回溯现在在内联存在的情况下是准确的。为了以编程方式检索回溯,应用程序应使用 runtime.CallersFrames 而不是直接遍历 runtime.Callers 的结果。

在 Windows 上,当程序处于空闲状态时,Go 不再强制系统计时器以高分辨率运行。这应该可以减少 Go 程序对电池寿命的影响。

在 FreeBSD 上,GOMAXPROCSruntime.NumCPU 现在基于进程的 CPU 掩码,而不是 CPU 的总数。

运行时对 Android O 具有初步支持。

runtime/debug

使用负值调用 SetGCPercent 不再运行立即垃圾回收。

runtime/trace

执行跟踪现在显示标记辅助事件,这些事件指示应用程序 goroutine 何时被迫协助垃圾回收,因为它分配得太快。

“清除”事件现在涵盖了为分配查找可用空间的整个过程,而不是记录每个单独的被清除的跨度。这减少了跟踪分配密集型程序时的分配延迟。清除事件显示清除了多少字节以及回收了多少字节。

sync

Mutex 现在更公平。

syscall

新的字段 Credential.NoSetGroups 控制 Unix 系统在启动新进程时是否进行 setgroups 系统调用以设置辅助组。

新的字段 SysProcAttr.AmbientCaps 允许在创建新进程时在 Linux 4.3+ 上设置环境能力。

在 64 位 x86 Linux 上,使用 CLONE_VFORKCLONE_VM 优化了进程创建延迟。

新的 Conn 接口描述了 net 包中的一些类型,这些类型可以使用新的 RawConn 接口访问其底层文件描述符。

testing/quick

该包现在在生成 int64uint64 随机数时选择完整范围内的值;在早期版本中,生成的值始终限于 [-262, 262) 范围。

在以前的版本中,使用 nil Config.Rand 值会导致使用固定的确定性随机数生成器。现在它使用一个用当前时间播种的随机数生成器。对于旧的行为,将 Config.Rand 设置为 rand.New(rand.NewSource(0))

text/template

空块的处理,该处理因 Go 1.8 的更改而被破坏(该更改使结果依赖于模板的顺序),已修复,恢复了旧的 Go 1.7 行为。

time

新的方法 Duration.RoundDuration.Truncate 处理将持续时间四舍五入和截断为给定持续时间的倍数。

在 Wine 下检索时间和睡眠现在可以正常工作。

如果 Time 值具有单调时钟读数,则其字符串表示(由 String 返回)现在包含一个最终字段 "m=±value",其中 value 是以秒为单位的小数格式的单调时钟读数。

包含的 tzdata 时区数据库已更新至 2017b 版本。与往常一样,它仅在系统没有可用的数据库时才会使用。