Go 1.9 发布说明

Go 1.9 简介

最新的 Go 版本 1.9 在 Go 1.8 发布六个月后推出,是 Go 1.x 系列的第十个版本。语言方面有两项更改:增加了对类型别名的支持,并定义了实现何时可以融合浮点运算。大部分更改都在工具链、运行时和库的实现中。一如既往,此版本保持了 Go 1 兼容性承诺。我们预计几乎所有 Go 程序都能像以前一样继续编译和运行。

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

语言变化

语言方面有两项更改。

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

type T1 = T2

此声明为 T2 所表示的类型引入了一个别名 T1——一个替代拼写;也就是说,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 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 在 Go 1.9 开发周期中停止运行 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 输出,而不是默认的特定于操作系统的输出格式。

Test

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

Pprof

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

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

Vet

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

Gccgo

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

运行时

包含内联帧的调用堆栈

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

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

在特定深度查询单个调用方的代码应使用 Caller,而不是向 Callers 传递长度为 1 的切片。

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

性能

一如既往,更改通用且多样,因此很难对性能做出精确的说明。由于垃圾收集器提速、更好的生成代码和核心库中的优化,大多数程序应该运行得更快一些。

垃圾收集器

以前会触发“停顿世界”垃圾收集的库函数现在会触发并发垃圾收集。具体来说,runtime.GCdebug.SetGCPercentdebug.FreeOSMemory 现在会触发并发垃圾收集,只阻塞调用 goroutine 直到垃圾收集完成。

如果由于新的 GOGC 值而立即需要垃圾收集,debug.SetGCPercent 函数才会触发垃圾收集。这使得可以即时调整 GOGC。

在使用包含许多大对象的大型(>50GB)堆的应用程序中,大对象分配性能显著提高。

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

标准库

透明单调时间支持

time 包现在透明地跟踪每个 Time 值中的单调时间,使得在存在挂钟调整的情况下计算两个 Time 值之间的时间变得安全。有关详细信息,请参阅包文档设计文档

新的位操作包

Go 1.9 包含一个新包 math/bits,其中包含用于操作位的优化实现。在大多数架构上,此包中的函数还会被编译器识别并视为内部函数,以获得额外的性能。

测试辅助函数

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

并发映射

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

Profiler 标签

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 现在包含在证书搜索路径中。

该包现在支持名称约束中的排除域。除了强制执行此类约束外,如果提供的模板证书填充了新的字段 ExcludedDNSDomainsCreateCertificate 将创建具有排除名称约束的证书。

如果证书中存在任何 SAN 扩展(包括没有 DNS 名称的扩展),则将忽略 Subject 中的 Common Name。在之前的版本中,代码仅测试证书中是否存在 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 的迁移。)

图像

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 提供了对连接底层文件描述符的访问。

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

net/http

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

服务器更改

  • ServeMux 现在在匹配处理程序时忽略主机头中的端口。对于 CONNECT 请求,主机未经修改地进行匹配。
  • 新的 Server.ServeTLS 方法包装了 Server.Serve,并增加了 TLS 支持。
  • Server.WriteTimeout 现在适用于 HTTP/2 连接,并按流强制执行。
  • HTTP/2 现在默认使用优先级写入调度器。帧按照 RFC 7540 第 5.3 节所述的 HTTP/2 优先级进行调度。
  • StripPrefix 返回的 HTTP 处理程序现在使用修改后的原始 *http.Request 克隆调用其提供的处理程序。任何将按请求状态存储在以 *http.Request 为键的映射中的代码都应改用 Request.ContextRequest.WithContextcontext.WithValue
  • LocalAddrContextKey 现在包含连接的实际网络地址,而不是监听器使用的接口地址。

客户端和传输更改

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 上,Args 现在在没有 shell32.dll 的情况下填充,将进程启动时间缩短了 1-7 毫秒。

os/exec

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

os/user

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

CGO_ENABLED=0 时,LookupGroupLookupGroupId 现在在 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 因为分配过快而被强制协助垃圾收集时。

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

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 版本。一如既往,只有在系统尚无该数据库时才使用它。