Go 1.3 发布说明
Go 1.3 简介
最新的 Go 版本 1.3 在 1.2 发布六个月后发布,并且没有包含任何语言更改。它主要侧重于实现工作,提供了精确的垃圾回收,对编译器工具链进行了重大重构,从而使构建速度更快,尤其是在大型项目中,总体性能显著提升,并支持 DragonFly BSD、Solaris、Plan 9 和 Google 的原生客户端架构 (NaCl)。它还对内存模型进行了一项重要的改进,涉及同步问题。与往常一样,Go 1.3 保持了兼容性承诺,并且几乎所有内容在迁移到 1.3 后都将继续编译和运行而无需更改。
对支持的操作系统和架构的更改
删除对 Windows 2000 的支持
微软于 2010 年停止支持 Windows 2000。由于它在异常处理(在 Unix 术语中为信号)方面存在实现困难,因此从 Go 1.3 开始,Go 也不再支持它。
支持 DragonFly BSD
Go 1.3 现在包括对 amd64
(64 位 x86)和 386
(32 位 x86)架构上的 DragonFly BSD 的实验性支持。它使用 DragonFly BSD 3.6 或更高版本。
支持 FreeBSD
当时没有宣布,但自从 Go 1.2 发布以来,在 FreeBSD 上使用 Go 需要 FreeBSD 8 或更高版本。
从 Go 1.3 开始,在 FreeBSD 上使用 Go 需要内核在编译时配置 COMPAT_FREEBSD32
标志。
与切换到 ARM 平台的 EABI 系统调用相一致,Go 1.3 将只在 FreeBSD 10 上运行。x86 平台(386 和 amd64)不受影响。
支持原生客户端
对原生客户端虚拟机架构的支持已在 Go 1.3 版本中恢复。它在 32 位 Intel 架构 (GOARCH=386
) 上运行,也运行在 64 位 Intel 上,但使用 32 位指针 (GOARCH=amd64p32
)。ARM 上尚不支持原生客户端。请注意,这是原生客户端 (NaCl),而不是可移植原生客户端 (PNaCl)。有关原生客户端的详细信息,请访问此处;有关如何设置 Go 版本的说明,请访问此处。
支持 NetBSD
从 Go 1.3 开始,在 NetBSD 上使用 Go 需要 NetBSD 6.0 或更高版本。
支持 OpenBSD
从 Go 1.3 开始,在 OpenBSD 上使用 Go 需要 OpenBSD 5.5 或更高版本。
支持 Plan 9
Go 1.3 现在包括对 386
(32 位 x86)架构上的 Plan 9 的实验性支持。它需要 Tsemacquire
系统调用,该调用自 2012 年 6 月以来一直存在于 Plan 9 中。
支持 Solaris
Go 1.3 现在包括对 amd64
(64 位 x86)架构上的 Solaris 的实验性支持。它需要 illumos、Solaris 11 或更高版本。
内存模型的更改
Go 1.3 内存模型添加了一条新规则,涉及在带缓冲区的通道上发送和接收,以明确带缓冲区的通道可以用作简单的信号量,使用发送到通道来获取,并使用从通道接收来释放。这不是语言更改,只是对通信的预期属性的澄清。
对实现和工具的更改
堆栈
Go 1.3 已将 goroutine 堆栈的实现从旧的“分段”模型更改为连续模型。当 goroutine 需要比可用堆栈更多的堆栈时,其堆栈将转移到更大的单个内存块。此传输操作的开销可以很好地摊销,并消除了当计算反复跨越段边界时的旧“热点”问题。包括性能数据在内的详细信息在此设计文档中。
对垃圾回收器的更改
一段时间以来,垃圾回收器在检查堆中的值时一直是精确的;Go 1.3 版本将等效的精度添加到堆栈上的值。这意味着非指针 Go 值(例如整数)永远不会被误认为是指针,并阻止未使用的内存被回收。
从 Go 1.3 开始,运行时假设具有指针类型的变量包含指针,而其他变量不包含指针。此假设是堆栈扩展和垃圾回收的精确行为的基础。使用unsafe 包在指针类型值中存储整数的程序是非法的,如果运行时检测到此行为,则将崩溃。使用unsafe 包在整数类型值中存储指针的程序也是非法的,但在执行期间更难诊断。由于指针对运行时隐藏,因此堆栈扩展或垃圾回收可能会回收它们指向的内存,从而创建悬空指针。
更新:使用 unsafe.Pointer
将内存中保存的整数类型值转换为指针的代码是非法的,必须重写。此类代码可以通过 go vet
识别。
映射迭代
对小型映射的迭代不再以一致的顺序发生。Go 1 定义“映射上的迭代顺序未指定,并且不保证在每次迭代中都相同。”为了防止代码依赖于映射迭代顺序,Go 1.0 在映射中的随机索引处启动每个映射迭代。Go 1.1 中引入的一个新的映射实现忽略了对具有八个或更少条目的映射进行迭代随机化,尽管迭代顺序仍然可能因系统而异。这使得人们能够编写依赖于小型映射迭代顺序的 Go 1.1 和 Go 1.2 程序,因此只能在某些系统上可靠地工作。Go 1.3 重新引入了对小型映射的随机迭代,以消除这些错误。
更新:如果代码假设小型映射的固定迭代顺序,它将中断并且必须重写,不要进行该假设。由于只有小型映射受到影响,因此问题最常出现在测试中。
链接器
作为对 Go 链接器进行一般大修的一部分,编译器和链接器已重构。链接器仍然是一个 C 程序,但现在作为链接器一部分的指令选择阶段已通过创建名为 liblink
的新库而移动到编译器。通过仅在第一次编译包时执行指令选择,这可以显着加快大型项目的编译速度。
更新:尽管这是一个重大的内部更改,但它不应影响程序。
gccgo 的状态
GCC 4.9 版本将包含 Go 1.2(而不是 1.3)版本的 gccgo。GCC 和 Go 项目的发布计划不一致,这意味着 1.3 将在开发分支中可用,但下一个 GCC 版本 4.10 可能会包含 Go 1.4 版本的 gccgo。
对 go 命令的更改
cmd/go
命令有几个新功能。go run
和 go test
子命令支持新的 -exec
选项来指定运行结果二进制文件的备用方式。它的直接目的是支持 NaCl。
go test
子命令的测试覆盖率支持现在在启用竞争检测器时自动将覆盖率模式设置为 -atomic
,以消除有关对覆盖率计数器的不安全访问的错误报告。
go test
子命令现在始终构建包,即使它没有测试文件。以前,如果不存在测试文件,它将不执行任何操作。
go build
子命令支持新的 -i
选项来安装指定目标的依赖项,但不安装目标本身。
现在支持启用cgo
的交叉编译。在运行 all.bash 时,使用 CC_FOR_TARGET 和 CXX_FOR_TARGET 环境变量分别指定 C 和 C++ 代码的交叉编译器。
最后,go 命令现在支持通过 cgo 导入 Objective-C 文件(后缀为 .m
)的包。
对 cgo 的更改
cmd/cgo
命令(处理 Go 包中的 import "C"
声明)已修复一个严重的错误,该错误可能导致某些包停止编译。以前,所有指向不完整结构体类型的指针都转换为 Go 类型 *[0]byte
,其效果是 Go 编译器无法诊断将一种结构体指针传递给期望另一种结构体指针的函数。Go 1.3 通过将每个不同的不完整结构体转换为不同的命名类型来纠正此错误。
给定 C 声明 typedef struct S T
用于不完整的 struct S
,一些 Go 代码使用此错误来互换引用类型 C.struct_S
和 C.T
。Cgo 现在明确允许这种用法,即使对于已完成的结构体类型也是如此。但是,一些 Go 代码也使用此错误将(例如)*C.FILE
从一个包传递到另一个包。这是非法的,并且不再有效:通常,Go 包应避免在其 API 中公开 C 类型和名称。
更新:混淆指向不完整类型的指针或跨包边界传递它们的代码将不再编译,并且必须重写。如果转换正确并且必须保留,请使用通过unsafe.Pointer
进行的显式转换。
使用 SWIG 的程序需要 SWIG 3.0
对于使用 SWIG 的 Go 程序,现在需要 SWIG 3.0 版本。cmd/go
命令现在将 SWIG 生成的目标文件直接链接到二进制文件中,而不是使用共享库构建和链接。
命令行标志解析
在 gc 工具链中,汇编器现在使用与 Go flag 包相同的命令行标志解析规则,这与传统的 Unix 标志解析有所不同。这可能会影响直接调用该工具的脚本。例如,go tool 6a -SDfoo
现在必须写成 go tool 6a -S -D foo
。(此更改已在 Go 1.1 中应用于编译器和链接器。)
godoc 的更改
当使用 -analysis
标志调用时,godoc 现在对它索引的代码执行复杂的静态分析。分析结果在源代码视图和包文档视图中均有显示,包括每个包的调用图以及定义和引用、类型及其方法、接口及其实现、通道上的发送和接收操作、函数及其调用者以及调用站点及其被调用者之间的关系。
其他更改
用于比较基准测试运行之间性能的程序 misc/benchcmp
已重写。它以前是主存储库中的 shell 和 awk 脚本,现在是 go.tools
存储库中的 Go 程序。文档在此处。
对于我们中少数构建 Go 发行版的人来说,工具 misc/dist
已移动并重命名;它现在位于主存储库中的 misc/makerelease
中。
性能
由于运行时和垃圾回收的更改,以及对库的一些更改,此版本的 Go 二进制文件的性能在许多情况下都有所提高。重要的示例包括
- 运行时更有效地处理延迟函数,从而减少了每个调用延迟函数的 goroutine 的内存占用量约 2 KB。
- 垃圾回收器已加速,使用了并发扫描算法、更好的并行化和大页面。累积效果可以将收集器暂停时间减少 50% 到 70%。
- 竞争检测器(参见本指南)现在快了约 40%。
- 正则表达式包
regexp
由于实现了第二个单遍执行引擎,因此对于某些简单的表达式现在快得多。使用哪个引擎的选择是自动的;详细信息对用户隐藏。
此外,运行时现在在堆栈转储中包含 goroutine 被阻塞了多长时间,这在调试死锁或性能问题时可能是有用的信息。
标准库的更改
新包
一个新的包debug/plan9obj
已添加到标准库中。它实现了对 Plan 9 a.out 对象文件的访问。
库的主要更改
crypto/tls
中之前的一个错误使得在 TLS 中无意中跳过验证成为可能。在 Go 1.3 中,此错误已修复:必须指定 ServerName 或 InsecureSkipVerify,如果指定了 ServerName,则会强制执行。这可能会破坏依赖于不安全行为的现有代码。
标准库中添加了一个重要的新的类型:sync.Pool
。它提供了一种有效的机制来实现某些类型的缓存,这些缓存的内存可以由系统自动回收。
testing
包的基准测试辅助函数B
现在有一个RunParallel
方法,以便更容易运行利用多个 CPU 的基准测试。
更新:crypto/tls
修复可能会破坏现有代码,但此类代码有误,应更新。
库的次要更改
以下列表总结了对库的一些次要更改,主要是添加。有关每个更改的更多信息,请参阅相关的包文档。
- 在
crypto/tls
包中,一个新的DialWithDialer
函数允许使用现有的拨号器建立 TLS 连接,从而更容易控制拨号选项(如超时)。该包现在还在ConnectionState
结构中报告连接使用的 TLS 版本。 crypto/x509.CreateCertificate
函数现在支持解析(以及在其他地方序列化)PKCS #10 证书签名请求。fmt
包的格式化打印函数现在将%F
定义为打印浮点值时%f
的同义词。math/big
包的Int
和Rat
类型现在实现了encoding.TextMarshaler
和encoding.TextUnmarshaler
。- 复数幂函数
Pow
现在指定了第一个参数为零时的行为。它以前是未定义的。详细信息在函数文档中。 net/http
包现在在新的Response.TLS
字段中公开了用于发出客户端请求的 TLS 连接的属性。net/http
包现在允许使用Server.ErrorLog
设置可选的服务器错误日志记录器。默认值仍然是所有错误都输出到标准错误。net/http
包现在支持使用Server.SetKeepAlivesEnabled
在服务器上禁用 HTTP 保持活动连接。默认值仍然是服务器默认启用保持活动(为多个请求重用连接)。只有资源受限的服务器或正在进行优雅关闭的服务器才会想要禁用它们。net/http
包添加了一个可选的Transport.TLSHandshakeTimeout
设置,以限制 HTTP 客户端请求等待 TLS 握手完成的时间。它现在也已在DefaultTransport
上默认设置。net/http
包的DefaultTransport
(由 HTTP 客户端代码使用)现在默认启用TCP 保持活动。其他具有空Dial
字段的Transport
值继续与以前一样工作:不使用 TCP 保持活动。net/http
包现在在使用ListenAndServe
或ListenAndServeTLS
时为传入的服务器请求启用TCP 保持活动。当服务器以其他方式启动时,不会启用 TCP 保持活动。net/http
包现在提供了一个可选的Server.ConnState
回调,以挂钩服务器连接生命周期的各个阶段(参见ConnState
)。这可用于实现速率限制或优雅关闭。net/http
包的 HTTP 客户端现在有一个可选的Client.Timeout
字段,用于指定对使用客户端发出的请求进行端到端超时。net/http
包的Request.ParseMultipartForm
方法现在将在主体Content-Type
不是multipart/form-data
时返回错误。在 Go 1.3 之前,它会静默失败并返回nil
。依赖于先前行为的代码应更新。- 在
net
包中,Dialer
结构现在有一个KeepAlive
选项,用于指定连接的保持活动周期。 net/http
包的Transport
现在始终关闭Request.Body
,即使出错也是如此。os/exec
包现在实现了文档中关于二进制文件的相对路径一直以来所说的内容。特别是,它仅在二进制文件的文件名不包含路径分隔符时才调用LookPath
。reflect.Value.SetMapIndex
函数不再在从空映射中删除时出现恐慌。- 如果主 goroutine 调用
runtime.Goexit
并且所有其他 goroutine 都完成了执行,则程序现在始终崩溃,并报告检测到的死锁。早期版本的 Go 对这种情况处理不一致:大多数实例都被报告为死锁,但一些微不足道的案例则干净地退出。 runtime/debug
包现在有一个新的函数debug.WriteHeapDump
,用于输出堆的描述。strconv.CanBackquote
函数现在认为DEL
字符U+007F
是非打印字符。syscall
包现在提供SendmsgN
作为Sendmsg
的备用版本,它返回写入的字节数。- 在 Windows 上,
syscall
包现在通过添加一个新的函数NewCallbackCDecl
(与现有的函数NewCallback
并排)来支持 cdecl 调用约定。 testing
包现在诊断调用panic(nil)
的测试,这些测试几乎总是错误的。此外,测试现在即使在失败时也会写入配置文件(如果使用概要分析标志调用)。unicode
包和整个系统中的相关支持已从 Unicode 6.2.0 升级到Unicode 6.3.0。