golang1.24新特性介绍

Go 1.24 与今日(2025.2.11)发布。本次更新在语言特性、工具链、运行时、标准库等方面带来多项重要改进。本文将分类总结这些新特性,帮助开发者快速了解版本亮点。

如果要体验这个版本,可以通过以下命令安装:

go install golang.org/dl/go1.24rc2@latest

语言特性

阅读更多

golang运行时源码解读-Goroutine

前言

Goroutine 是 Go 语言的并发执行单元,是Go语言并发的基础。本文将从源码的角度,解读Goroutine的创建、销毁、状态转移等过程。

协程数据结构

type g struct {
// 栈参数。
// stack 描述了实际的栈内存:[stack.lo, stack.hi)。
// stackguard0 是在 Go 栈增长序言中比较的栈指针。
// 它通常是 stack.lo+StackGuard,但可以是 StackPreempt 以触发抢占。
// stackguard1 是在 //go:systemstack 栈增长序言中比较的栈指针。
// 它在 g0 和 gsignal 栈上是 stack.lo+StackGuard。
// 在其他协程栈上是 ~0,以触发对 morestackc 的调用(并崩溃)。
stack stack // 偏移量已知 runtime/cgo
stackguard0 uintptr // 偏移量已知 liblink
stackguard1 uintptr // 偏移量已知 liblink

_panic *_panic // 最内层的 panic - 偏移量已知 liblink
_defer *_defer // 最内层的 defer
m *m // 当前执行的 m; 偏移量已知 arm liblink
sched gobuf // 调度相关信息
syscallsp uintptr // 如果 status==Gsyscall,syscallsp = sched.sp 用于 gc
syscallpc uintptr // 如果 status==Gsyscall,syscallpc = sched.pc 用于 gc
syscallbp uintptr // 如果 status==Gsyscall,syscallbp = sched.bp 用于 fpTraceback
stktopsp uintptr // 栈顶的预期 sp,用于 traceback 检查
// param 是一个通用指针参数字段,用于在特定上下文中传递值,
// 这些上下文中找到其他存储参数的地方会很困难。它目前有四种用法:
// 1. 当一个通道操作唤醒一个阻塞的协程时,它将 param 设置为指向已完成的阻塞操作的 sudog。
// 2. 由 gcAssistAlloc1 用于向其调用者发信号,表明协程完成了 GC 周期。以其他方式这样做是不安全的,因为协程的栈可能在此期间已移动。
// 3. 由 debugCallWrap 用于将参数传递给一个新的协程,因为在运行时分配闭包是被禁止的。
// 4. 当一个 panic 被恢复并且控制返回到相应的帧时,param 可能指向一个 savedOpenDeferState。
param unsafe.Pointer
atomicstatus atomic.Uint32
stackLock uint32 // sigprof/scang 锁;TODO: 合并到 atomicstatus
goid uint64
schedlink guintptr
waitsince int64 // 大约阻塞的时间
waitreason waitReason // 如果 status==Gwaiting

preempt bool // 抢占信号,重复 stackguard0 = stackpreempt
preemptStop bool // 在抢占时转换为 _Gpreempted;否则,只是取消调度
preemptShrink bool // 在同步安全点缩小栈

// asyncSafePoint 表示 g 是否在异步安全点停止。这意味着栈上有没有精确指针信息的帧。
asyncSafePoint bool

paniconfault bool // 在意外的故障地址上 panic(而不是崩溃)
gcscandone bool // g 已扫描栈;受 status 中的 _Gscan 位保护
throwsplit bool // 不得分割栈
// activeStackChans 表示是否有未锁定的通道指向此协程的栈。如果为 true,栈复制需要获取通道锁以保护这些栈区域。
activeStackChans bool
// parkingOnChan 表示协程即将停放在 chansend 或 chanrecv 上。用于在栈缩小时发出不安全点信号。
parkingOnChan atomic.Bool
// inMarkAssist 表示协程是否在标记辅助中。由执行跟踪器使用。
inMarkAssist bool
coroexit bool // 协程切换时的参数

raceignore int8 // 忽略竞争检测事件
nocgocallback bool // 是否禁用从 C 回调
tracking bool // 是否跟踪此 G 的调度延迟统计
trackingSeq uint8 // 用于决定是否跟踪此 G
trackingStamp int64 // G 最后一次开始被跟踪的时间戳
runnableTime int64 // 可运行时间,在运行时清除,仅在跟踪时使用
lockedm muintptr
sig uint32
writebuf []byte
sigcode0 uintptr
sigcode1 uintptr
sigpc uintptr
parentGoid uint64 // 创建此协程的协程的 goid
gopc uintptr // 创建此协程的 go 语句的 pc
ancestors *[]ancestorInfo // 创建此协程的祖先协程信息(仅在 debug.tracebackancestors 时使用)
startpc uintptr // 协程函数的 pc
racectx uintptr
waiting *sudog // 此 g 正在等待的 sudog 结构(具有有效的 elem 指针);按锁顺序排列
cgoCtxt []uintptr // cgo 回溯上下文
labels unsafe.Pointer // 分析器标签
timer *timer // 缓存的 time.Sleep 定时器
sleepWhen int64 // 何时休眠
selectDone atomic.Uint32 // 我们是否参与了 select 并且有人赢得了比赛

// goroutineProfiled 表示此协程的栈在当前进行中的协程分析中的状态
goroutineProfiled goroutineProfileStateHolder

coroarg *coro // 协程切换期间的参数

// 每个 G 的跟踪器状态。
trace gTraceState

// 每个 G 的 GC 状态

// gcAssistBytes 是此 G 的 GC 辅助信用,以分配的字节数表示。如果这是正数,则 G 有信用可以分配 gcAssistBytes 字节而无需辅助。如果这是负数,则 G 必须通过执行扫描工作来纠正此问题。我们以字节为单位跟踪这个,以便在 malloc 热路径中快速更新和检查债务。辅助比率决定了这与扫描工作债务的对应关系。
gcAssistBytes int64
}

协程的创建

阅读更多

golang上下文切换测试

引入

golang是一门高性能的编程语言,基于其轻量,高效的的Goroutine的设计,可以实现很小的协程切换开销。
本文将解释一下基本的协程相关的原理,并实际做一个小的测试,去得到其实际的切换开销

原理

协程

协程(Coroutine)是一种更轻量级的并发编程方式,他是在用户态实现的,相比于线程进程更加轻量,拥有更小的上下文切换开销,栈空间等等。
协程主要分为两种类型:

阅读更多

go项目依赖关系可视化

概述

将go的依赖进行可视化,有助于排查解决依赖问题

go mod graph 输出项目的依赖关系,通过modgraphviz 转换格式后,就可以被 graphviz 可视化了

准备

modgraphviz : 格式转换工具

阅读更多