likes
comments
collection
share

Golang 1.23 有什么变化

作者站长头像
站长
· 阅读数 24

截止到目前为止,go1.23的正式版还没有发布,但是其预发布版本,也就是rc版本已经开放下载了,预发布与正式版在功能特性上是一致的,很少会发生变化。通过官网的Release Notes,可以解读到1.23有哪些新特性和提升。

官方Release Notes: https://tip.golang.org/doc/go1.23

安装:

go install golang.org/dl/go1.23rc1@latest
go1.23rc1 download

【最重要】支持使用关键字range实现用户自定义的遍历函数

range关键字在golang中一直只能遍历切片、map等内置数据结构。实际上,从1.22开始,golang就开始支持,处于实验性质,需要在运行时加上参数GOEXPERIMENT=rangefunc,从1.23开始,在语法层面直接支持用户自定义函数(迭代器),不需要加任何参数。支持3种返回值的遍历,分别是0、1、2个返回值的遍历,函数格式分别是:

var zeroReturn func(func() bool)  
var oneReturn func(func(K) bool)
var twoReturn func(func(K, V) bool)

for range zeroReturn {
}
for key := range oneReturn {
}
for key, value := range twoReturn {
}

// If break in for range call, yield return true 
func twoReturnExample(yield func(index int, arr string) bool) {
	for i := 0; i < 10; i++ {
		if !yield(i, fmt.Sprintf("I'm %d ", i)) {
			return
		}
	}
}

for k,v := range twoReturnExample {
   if k == 2 {
     break 
   }
   fmt.Println(v)
}
// This example will print: 
// I'm 0
// I'm 1

标准库中新增的标准库iter是迭代器的类型定义(就是我上面例子中的zeroReturn等几个函数)。 maps和slices中新增了很多围绕迭代器的方法(下面也会有介绍)。

官方文档:tip.golang.org/wiki/Rangef…

Demo: github.com/jin06/examp…

【比较重要】标准库中Timer和Ticker的改动

首先,Timer和Ticker的垃圾回收进行了特殊的处理,早期版本需要调用调用Stop方法才会被垃圾回收期回收,因为Timer和Ticker的实现原理是独立的goroutine定时向chan写入数据。所以如果不调用Stop方法会造成goroutine泄露,现在的优化跳过了常规的goroutine回收和chan回收,做了特殊的优化,即便不调用Stop方法,运行时也会检查并回收不用的Timer和Ticker。这个bug还是非常常见的,我就在实际工作中发现过很多同事的代码中会犯这种错误,所以这个优化还是非常有用的。

第二,Timer、Ticker改为使用非缓冲的chan。这种改动让我们写一些定时任务的时候更像linux crontab。因为很多时候Timer和Ticker都是做定时任务,任务执行如果超过了定时时间,则任务会一个接着一个做,所以这个改动更加合理,符合这两个结构体最大的应用场景需求。

【一般】新增iter标准库

因为从1.23,go正式引入用户自定义遍历函数的特性,这个包用于提供一些标准化的迭代器的结构体和方法。

API: pkg.go.dev/iter@master

【比较重要】标准库slices的改动

新增了一些方法:

All : 返回一个index,value的迭代器。(配合迭代器特性的)

Values:同All,区别只返回value的迭代器。

Backward:同All,遍历顺序相反。

Collect:将遍历函数的值写入一个slice中,传入迭代器,返回slice

func Collect[E any](seq iter.Seq[E]) []E

AppendSeq: 将迭代器的值追加到一个slice中。

Sorted: 同Collect,写入后再对slice排序。

SortedFunc: 同Sorted,增加一个排序函数作为参数。

SortedStableFunc: 同SortedFunc,使用稳定排序(稳定排序不改变元素值相同的元素的在数组中的位置,例如[1 , 1] 排序后,两个元素在内存中不会交换位置)

Chunk:会传入一个数字,对slice按照数字进行切割,并返回若干迭代器。比如一个slice大小为10, 传入的数字为3, 调用Chunk函数会返回4个迭代器,其中前三个大小为3, 第四个大小为1,直接看例子会更加明显:pkg.go.dev/slices@mast…

API:pkg.go.dev/slices@mast…

【比较重要】标准库maps的改动

增加了几个函数,和slices包一样基本上也都是围绕迭代器的,命名基本也和slices包差不多,都是一些易用性的方法。例如

All 返回k,v 迭代器,Keys 返回k的迭代器,Values 返回v的迭代器。

【一般重要】新增标准库structs

这个包定义一些标记结构体,目前只有一个结构体HostLayout,如果结构体使用了HostLayout会改变结构体的内存布局(不知道具体的影响,没查到资料,有知道的吗?可以评论一下),用户自定义的结构体如果使用它有固定的格式, 下划线是变量名,如:

package main 
import "structs"

type My struct {
  _ structs.HostLayout
}

所以这个包我觉得对具体代码逻辑没有用,是用告诉速运行时、编译器改变一些结构体的底层逻辑,如内存布局等,优化性能可能会有帮助吧,所以未来我觉得还是有一定的意义。

【没什么用】新增unique标准库

提供可比较的数据类型的标准,目前该库只实现了一个Handle[T]的结构体,方法包括Make用于生成一个结构体,Value用于返回结构体持有的值。实际上这个库没有建设完,和我们直接比较两个值是一样的,使用这个库还要额外增加代码。只不过这个库在内存层面做了优化,如果调用Make方法创建Handle对象时已经存在相同的值创建的Handle对象,那么此时不会消耗多余的内存,而是直接引用之前创建好的对象。在类型比较时可以提升一点点性能,个人认为这个库目前没什么用处可以忽略它。使用方法如下:

package main 
import "unique"
func main() {
  h := unique.Make[string]("a")
  check := unique.Make[string]("b")
  fmt.Println(h==check)
}

API: pkg.go.dev/unique@mast…

【不重要】其他的标准库小改动(略)

都是增加一些易用性的方法,没有特别重大的改进。如:

生成uint为随机数的方法。

返回一个别名类型的原始的类型。

RuneLen方法如果传递的参数不是何方的utf-16则返回-1

等等

【不重要】工具链遥测,收集使用和崩溃数据帮助Go团队改进

Go1.23 开始Go工具链手机使用数据和崩溃数据帮助Go团队定位问题,改进代码。这项功能在本地命令打开或关闭,打开关闭方式:

// 安装命令
go install golang.org/x/telemetry/cmd/gotelemetry@latest
// 数据收集到本地,每周上传到
gotelemetry on
// 捕收剂数据,也不上传数据
gotelemetry off

更详细的使用说明:tip.golang.org/doc/telemet…

数据上传地址:telemetry.go.dev/

【一般】其他的变化

  • go tool cgo 命令支持 -ldflags 参数

使用这个参数可以传递CGO_LDFLAGS参数,避免环境变量CGO_LDFLAGS过大的错误。这个是指导使用哪个C的库文件等配置。

  • go.mod 增加 debug信息

在go.mod文件中增加的配置,配置debug的行为

godebug (
    default=go1.21
    panicnil=1
    asynctimerchan=0
)

更详细的说明:tip.golang.org/doc/godebug

  • go vet 静态分析支持 stdversion
  • go trace

有优化,程序可恢复的场景更多

  • 运行时优化

崩溃时打印的调用栈更有区分度,阅读更友好。goroutine崩溃后,打印的调用栈后,会折叠后续的goroutine的调用栈输出。

  • 编译器的优化

Profile-guided optimization(PGO)优化,主要体现在编译时间上,使用PGO原来会增加一倍的编译时间,现在只增加少量的编译时间(小于10%)

空间使用也会减少,减少的幅度不大,而且主要是amd64和386平台。

PGO是Go1.21引进的新技术,用于编译优化的技术,利用profile数据对代码进行优化,提升性能。更多的关于PGO的详细资料:

tip.golang.org/doc/pgo

  • (一般重要)连接器的优化 (对linkname的限制)

在标准库和运行时代码中禁止使用 //go:linkname 。原有的还支持,新增的使用进行了限制。

关于linkname补充一下,在代码中使用linkname标签可以将方法指向另一个方法,可以导出保内使用的方法、变量。这种方式存在的问题是,被导出方是无感的。1.23做了一些限制:

  1. 在标准库中限制linkname的使用,只能使用handshake模式(被导出方也需要显示的增加linkanme标签),并且开启 -checklinkname=1标识才可以使用
  2. 目前没有限制非标准库的使用

可以看一下这个文档github.com/golang/go/i…

转载自:https://juejin.cn/post/7385776238788788233
评论
请登录