Go 1.9 版本说明
Go 1.9 简介
最新的 Go 版本 1.9 在 Go 1.8 发布六个月后发布,是 Go 1.x 系列 的第十个版本。有两个 语言更改:添加对类型别名的支持,以及定义实现何时可以融合浮点运算。大多数更改是在工具链、运行时和库的实现中进行的。与往常一样,此版本维护了 Go 1 的 兼容性承诺。我们预计几乎所有 Go 程序都将继续像以前一样编译和运行。
此版本添加了 透明单调时间支持、并行编译包中的函数、更好地支持 测试辅助函数,并包含一个新的 位操作包 以及新的 并发映射类型。
语言更改
有两个语言更改。
Go 现在支持类型别名,以便在将类型从一个包移动到另一个包时支持逐步代码修复。 类型别名设计文档 和 一篇关于重构的文章 详细介绍了这个问题。简而言之,类型别名声明的形式为
type T1 = T2
此声明引入了别名 T1
(T2
的另一种写法)来表示 T2
所表示的类型;也就是说,T1
和 T2
表示相同的类型。
另一个较小的语言更改是, 语言规范现在说明 实现何时可以将浮点运算融合在一起,例如使用架构的“融合乘加”(FMA) 指令计算 x*y
+
z
,而无需对中间结果 x*y
进行舍入。若要强制执行中间舍入,请编写 float64(x*y)
+
z
。
移植
此版本中没有新的受支持操作系统或处理器架构。
ppc64x 需要 POWER8
GOARCH=ppc64
和 GOARCH=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。
GOARM
和 GO386
的值现在会影响已编译包的构建 ID(由 go
工具的依赖项缓存使用)。
汇编器
四操作数 ARM MULA
指令现在已正确汇编,其中加数寄存器为第三个参数,结果寄存器为第四个也是最后一个参数。在之前的版本中,这两个含义颠倒了。三操作数形式(其中第四个参数隐式与第三个参数相同)不受影响。使用四操作数 MULA
指令的代码将需要更新,但我们认为这种形式很少使用。MULAWT
和 MULAWB
在所有形式中都已使用正确的顺序,并且没有改变。
汇编器现在支持 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
vet
和 go
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.GC
、 debug.SetGCPercent
和 debug.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_FILE
和 SSL_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
来实现自己的参数检查器。这也允许驱动程序支持 OUTPUT
和 INOUT
参数类型。Out
应在驱动程序支持的情况下用于返回输出参数。
Rows.Scan
现在可以扫描用户定义的字符串类型。以前,该包支持扫描到数值类型,例如 type
Int
int64
。现在它还支持扫描到字符串类型,例如 type
String
string
。
新的 DB.Conn
方法返回新的 Conn
类型,该类型表示来自连接池的数据库的专有连接。在调用 Conn.Close
将连接返回连接池之前,在 Conn
上运行的所有查询都将使用相同的底层连接。
encoding/asn1
新的 NullBytes
和 NullRawValue
表示 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 哈希支持,分别使用 New128
和 New128a
。
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
新的 IsInt64
和 IsUint64
方法报告 Int
是否可以表示为 int64
或 uint64
值。
mime/multipart
新字段 FileHeader.Size
描述了多部分消息中文件的大小。
net
新的 Resolver.StrictErrors
提供了对 Go 内置 DNS 解析器如何处理由多个子查询(例如 A+AAAA 地址查找)组成的查询期间的临时错误的控制。
新的 Resolver.Dial
允许 Resolver
使用自定义拨号函数。
JoinHostPort
现在只在主机包含冒号时将地址放在方括号中。在之前的版本中,如果地址包含百分号 (’%
’) 符号,它也会将地址放在方括号中。
新的方法 TCPConn.SyscallConn
、IPConn.SyscallConn
、UDPConn.SyscallConn
和 UnixConn.SyscallConn
提供了对连接的底层文件描述符的访问权限。
现在,可以使用从 (*TCPListener).String()
获得的地址安全地调用 Dial
,前提是在使用 Listen(“tcp”, “:0”)
创建监听器之后。以前,它在某些具有半配置的 IPv6 堆栈的机器上失败。
net/http
Cookie.String
方法(用于 Cookie
和 Set-Cookie
标头)现在会在值包含空格或逗号时将值用双引号括起来。
服务器更改
-
ServeMux
现在在匹配处理程序时会忽略主机标头中的端口。对于CONNECT
请求,主机将保持不变地匹配。 -
新的
Server.ServeTLS
方法用添加的 TLS 支持包装Server.Serve
。 -
Server.WriteTimeout
现在适用于 HTTP/2 连接,并且在每个流上强制执行。 - HTTP/2 现在默认情况下使用优先级写入调度程序。框架会按照 HTTP/2 优先级(如 RFC 7540 第 5.3 节 中所述)进行调度。
-
由
StripPrefix
返回的 HTTP 处理程序现在会使用原始*http.Request
的修改后的克隆调用其提供的处理程序。任何将每个请求状态存储在以*http.Request
为键的映射中的代码都应使用Request.Context
、Request.WithContext
和context.WithValue
替代。 -
LocalAddrContextKey
现在包含连接的实际网络地址,而不是监听器使用的接口地址。
客户端和传输更改
-
当由
Transport.Proxy
返回的 URL 的方案为socks5
时,Transport
现在支持通过 SOCKS5 代理发出请求。
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
Lookup
和 LookupId
现在在 CGO_ENABLED=0
时在 Unix 系统上工作,方法是读取 /etc/passwd
文件。
LookupGroup
和 LookupGroupId
现在在 CGO_ENABLED=0
时在 Unix 系统上工作,方法是读取 /etc/group
文件。
reflect
新的 MakeMapWithSize
函数创建具有容量提示的映射。
runtime
运行时生成的并记录在配置文件中的回溯现在在内联存在的情况下是准确的。为了以编程方式检索回溯,应用程序应使用 runtime.CallersFrames
而不是直接遍历 runtime.Callers
的结果。
在 Windows 上,当程序处于空闲状态时,Go 不再强制系统计时器以高分辨率运行。这应该可以减少 Go 程序对电池寿命的影响。
在 FreeBSD 上,GOMAXPROCS
和 runtime.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_VFORK
和 CLONE_VM
优化了进程创建延迟。
新的 Conn
接口描述了 net
包中的一些类型,这些类型可以使用新的 RawConn
接口访问其底层文件描述符。
testing/quick
该包现在在生成 int64
和 uint64
随机数时选择完整范围内的值;在早期版本中,生成的值始终限于 [-262, 262) 范围。
在以前的版本中,使用 nil Config.Rand
值会导致使用固定的确定性随机数生成器。现在它使用一个用当前时间播种的随机数生成器。对于旧的行为,将 Config.Rand
设置为 rand.New(rand.NewSource(0))
。
text/template
空块的处理,该处理因 Go 1.8 的更改而被破坏(该更改使结果依赖于模板的顺序),已修复,恢复了旧的 Go 1.7 行为。
time
新的方法 Duration.Round
和 Duration.Truncate
处理将持续时间四舍五入和截断为给定持续时间的倍数。
在 Wine 下检索时间和睡眠现在可以正常工作。
如果 Time
值具有单调时钟读数,则其字符串表示(由 String
返回)现在包含一个最终字段 "m=±value"
,其中 value
是以秒为单位的小数格式的单调时钟读数。
包含的 tzdata
时区数据库已更新至 2017b 版本。与往常一样,它仅在系统没有可用的数据库时才会使用。