Go1.25 新特性:支持 FlightRecorder 模式、支持读取符号链接、OS 版本推进等

大家好,我是煎鱼。

最近 Go 在前几天已经发布了 Go1.25 的 RC1 版本:

这次还是比较准时的。之前 Go1.25 新特性我们也介绍了不少,今天分享一些零碎但偶尔可能需要关注的新特性点。

Go 所要求的 OS 版本推进

每次新版本迭代,都会迎来 OS 系统版本的进一步的新老推进,是我们需要及时关注的。为此之前还推进了测试老集群的版本升级。

  • MacOS 系统:从 Go1.25 版本起,需要 macOS 12 Monterey 或更高版本。对以前版本的支持已经停止。

  • Windows 系统:Go1.25 是最后一个包含对 32 位 Windows ARM 架构(GOOS=windows,GOARCH=arm) 支持的版本,这个移植版本存在问题(被称为“broken”)。

    • 从 Go1.26 开始,这个架构支持将被移除,即不再支持在 32 位的 Windows ARM 系统上编译或运行 Go 程序。

  • Linux 系统:内核方面没有新的变化要求。

Panic 输出日志更简洁

当程序因为一个未处理的 panic(已被 recover 后又重新 panic)而退出时,打印的信息现在不会再重复 panic 值的文本内容。

之前如果一个程序执行了 panic("PANIC"),然后通过 recover 捕获了这个 panic,接着又使用原始值重新 panic,他会打印:

panic: PANIC [recovered]
 panic: PANIC

现在,程序将改为打印:

panic: PANIC [recovered, repanicked]

本次 Go1.25 主要就是将两次 panic 输出的语义信息合并到一行中,并避免重复显示 panic 值 "PANIC",让日志更简洁清晰。

ReadLinkFS、DirFS 支持获取符号链接的指向位置

在 Go1.25 中,引入了一个新的接口,称为 ReadLinkFS。这个接口提供了读取文件系统中符号链接(symbolic links)的能力:

ReadLinkFS 对应的接口如下:

type ReadLinkFS interface {
 FS

// ReadLink returns the destination of the named symbolic link.
// If there is an error, it should be of type [*PathError].
 ReadLink(name string) (string, error)

// Lstat returns a [FileInfo] describing the named file.
// If the file is a symbolic link, the returned [FileInfo] describes the symbolic link.
// Lstat makes no attempt to follow the link.
// If there is an error, it should be of type [*PathError].
 Lstat(name string) (FileInfo, error)
}

ReadLinkFS 接口允许程序读取符号链接的目标路径。这意味着开发者可以通过该接口轻松地获取符号链接指向的实际文件或目录位置。

同时还包括对 os.DirFS 的改进,使其实现了 ReadLinkFS 接口:

这意味着在使用 os.DirFS 时,用户也可以利用该接口来处理符号链接。

TypeAssert 支持对值进行断言

在日常 Go 程序进行反射时,我们一般是使用 reflect.ValueOf 方法来进行。但是经过性能测试,发现了一些问题。

基准测试代码:

func Benchmark(b *testing.B) {
    // 通过反射创建一个可寻址的 time.Time 值
 v := reflect.ValueOf(new(time.Time)).Elem()
    // // 开启内存分配报告
 b.ReportAllocs()
 for i := 0; i < b.N; i++ {
      // 将反射值转为接口,再转回 time.Time
      _ = v.Interface().(time.Time)
 }
}

这段基准测试的目标是测量 v.Interface().(time.Time) 操作的性能和内存开销。

测试结果:

Benchmark-24     37673833         29.74 ns/op       24 B/op        1 allocs/op

需要重点关注的是:每次操作中发生了 1 次内存分配。

会有内存分配的原因是:

  • 由于 v 是一个可寻址的 time.Time 值(通过 Elem() 获取),Go 的 reflect.Value.Interface() 会复制这个值。

  • 复制的目的是:为了防止外部代码通过接口访问时直接修改原始数据(因为原始值是可寻址的,为了保持封装性和安全性)。

  • 这个复制过程会导致 一次堆内存分配(alloc),从而出现了 24 B/op 和 1 allocs/op

在前几年 tailscale 的 @Joe Tsai 大佬发现了这个问题,并提出了以下提案:

当时提案上希望增加 TypeAssert 的泛型方法:

// AssertTo is semantically equivalent to:
//    v2, ok := v.Interface().(T)
func AssertTo[T any](v reflect.Value "T any") (T, bool)

新增该方法后,其作用语义上等同于 v.Interface().(T),但有效避免了 interface 装箱带来的复制和堆分配。

从而在性能关键路径(例如:反射密集的场景)提供了更高效的替代方案。

后续的用法如下:

t, ok := reflect.AssertTo[time.Time](v "time.Time")
...

当然,最后到 Go1.25 函数的名字改了,改成以下函数签名:

func TypeAssert[T any](v Value "T any") (T, bool)

改名的原因是 rsc 认为:简单的 Assert 可能会与 C 风格的断言混淆。另外改名后有了 Type 前缀,也就不需要 To 后缀了。

trace 支持 FlightRecorder 模式

FlightRecorder 是什么

“Flight recording”(飞行记录)是一种技术,它将追踪数据保存在一个概念性的环形缓冲区中,并在需要时将其刷新。

该技术的目的是捕获程序中有趣行为的追踪数据,即使事先无法预测这些行为会在什么时候发生。

例如:

  • 当 Web 服务未通过健康检查,或者处理某个请求的时间异常过长时。

    • 具体来说,Web 服务可以在这些异常实际发生时检测到,但程序员在部署时却无法准确预知它们会在何时出现。

    • 而在异常发生之后再启动追踪往往并没有什么用,因为此时程序已经执行过了那些“有趣”的部分。

Go FlightRecorder 落地

Go 在 runtime 中能够做 FlightRecorder,还是得益于之前在以下 issues#60773 对 trace 做过大修和性能优化:

再同样由 @Michael Knyszek 提起以下 FlightRecorder 的正式提案和实现内容:

在 Go 中,所有追踪数据将被组织为一系列自包含的分区(partitions)。这一实现上的变更为 Go 的执行追踪器添加类似“飞行记录”的能力提供了机会 —— 即始终保留至少一个分区,可在任意时刻快照保存。

而正因为 issues#60773 的优化,Go trace 的性能有了大幅优化。长时间追踪下启用 FlightRecorder 已经足够轻量,不再是一个性能负担。从而在这个版本总算是实现了。

以下是 runtime/trace 包中的新 API,用于启用 FlightRecorder。大家可以自行在 Go 程序中进行触发。

如下 API 代码:

package trace

type FlightRecorder struct {
    ...
}

func (*FlightRecorder) SetMinAge(d time.Duration)

func (*FlightRecorder) MinAge() time.Duration

func (*FlightRecorder) SetMaxBytes(bytes uint64)

func (*FlightRecorder) MaxBytes() uint64

func (*FlightRecorder) Start() error

func (*FlightRecorder) Stop() error

func (*FlightRecorder) Enabled() bool

func (*FlightRecorder) WriteTo(w io.Writer) (n int64, err error)

完整的 API 文档可以到 runtime/trace@master#FlightRecorder[1] 进行查看。

总结

本次主要是针对一些细致的特性进行了说明,像是大家可以检查自己 macOS 是否符合新版本的诉求。之前我就有因此将 OS 和集群版本升级的诉求。

另外本次的 runtime/trace 的 FlightRecorder 模式支持将带来更多样的调试追踪的提效,反射中 TypeAssert 新方法支持带来的的性能优化、ReadLinkFS 和 DirFS 支持符合链接(软链)的读取,都是一些有实际效益的优化点。

参考资料

[1] 

runtime/trace@master#FlightRecorder: https://pkg.go.dev/runtime/trace@master#FlightRecorder

关注和加煎鱼微信,

一手消息和知识,拉你进技术交流群👇

你好,我是煎鱼,出版过 Go 畅销书《Go 语言编程之旅》,再到获得 GOP(Go 领域最有观点专家)荣誉,点击蓝字查看我的出书之路

日常分享高质量文章,输出 Go 面试、工作经验、架构设计,加微信拉读者交流群,和大家交流!

原创不易 点赞支持

内容概要:本文系统梳理了多个科研领域的前沿研究与技术实现,重点涵盖FDTD方法中的完美匹配层(PML)研究,以及Matlab/Simulink在电磁、电力、控制、通信、信号处理、图像处理、路径规划、能源系统优化等领域的仿真与算法实现。文中列举了大量基于Matlab和Python的科研案例,如风电功率预测、负荷预测、无人机三维路径规划、电池系统故障诊断、雷达模拟、通信编码、微电网优化调度等,并强调结合智能优化算法(如粒子群、遗传算法、深度学习等)提升系统性能。同时,提供了丰富的代码资源与仿真模型,涵盖永磁同步电机控制、逆变器设计、多智能体任务分配、虚拟电厂调度等复杂系统,助力科研人员快速开展复现实验与创新研究。; 适合人群:具备一定编程基础,熟悉Matlab/Python工具,从事电气工程、自动化、通信、人工智能、新能源、控制科学等相关领域研究的研发人员及研究生。; 使用场景及目标:① 学习并实现FDTD仿真中的PML边界条件以有效抑制数值反射;② 掌握Matlab/Simulink在多物理场建模、控制系统设计与优化算法中的综合应用;③ 借助提供的代码资源完成科研复现、课程设计、竞赛项目或工程原型开发; 阅读建议:此资源以科研实战为导向,不仅提供理论方法,更强调代码实现与仿真验证。建议读者结合自身研究方向,按目录顺序查阅相关模块,下载配套代码进行调试与二次开发,以达到学以致用、融会贯通的目的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值