当前位置: 首页 > news >正文

Golang Panic Throw Map/Channel 并发笔记

Golang Panic & Throw & Map/Channel 并发笔记


1. Panic 与 Recover

Golang中除了error外,还有直接终止程序的panic,有些panic可以被recover捕获,有些不能,这是怎么回事呢?先介绍一下:

1.1 普通 Panic

可以被捕获,而且也可以开发者手动触发,代码有时候不注意会写出系统报的panic,空指针啥的。

  • 通过 panic("message") 触发。
  • 会沿调用栈向上传播,执行 defer 链。
  • 可以用 recover() 捕获并恢复程序。
  • 示例:
defer func() {if r := recover(); r != nil {fmt.Println("Recovered:", r)}
}()
panic("boom!")

1.2 Throw(runtime fatal error)

这个就是不能被捕获的"panic",其实这个和上面的panic不是一个东西,但是都是会导致程序的终止,这个是开发者无法调用的。体现在源码里是throw()方法,很常见,例如runtime/chan.go中:

	// compiler checks this but be safe.if elem.Size_ >= 1<<16 {throw("makechan: invalid channel element type")}if hchanSize%maxAlign != 0 || elem.Align_ > maxAlign {throw("makechan: bad alignment")}mem, overflow := math.MulUintptr(elem.Size_, uintptr(size))if overflow || mem > maxAlloc-hchanSize || size < 0 {panic(plainError("makechan: size out of range"))}
  • 特性
    • 不是 panic,不创建 _panic 对象。
    • 不走 defer/recover 链。
    • 直接 fatal error,终止进程。
  • 示例:并发读写已初始化 map
m := make(map[int]int)
go func() { m[1] = 1 }()
_ = m[2] // concurrent map read and map write -> throw

2. Map 并发规则

map并发读写是会报不能recover的panic,但有个特例,就是这个map没初始化的时候,可以被recover。

情况map 是否 nil并发访问runtime 行为recover 可否
读取 nil map安全,返回零值n/a
写入 nil mappanic: assignment to entry in nil map✅ 可 recover
并发读写未初始化 mappanic: assignment to entry in nil map✅ 可 recov

可以用下面的例子体会一下:

fmt.Println("=== 1. 读取 nil map ===")
var nilMap map[int]int
fmt.Println(nilMap[1]) // 安全,返回零值fmt.Println("\n=== 2. 写入 nil map(panic,可 recover) ===")
func() {defer func() {if r := recover(); r != nil {fmt.Println("Recovered from panic:", r)}}()nilMap[1] = 100 // panic: assignment to entry in nil mapfmt.Println("这行不会执行")
}()fmt.Println("\n=== 3. 并发读写未初始化 map(panic, 可 recover) ===")
//m := make(map[int]int)
var m map[int]int
var wg sync.WaitGroupdefer func() {if r := recover(); r != nil {fmt.Println("Recovered:", r) // 这里不会被触发}
}()wg.Add(2)// 写 goroutine
go func() {defer wg.Done()defer func() {if r := recover(); r != nil {fmt.Println("Recovered:", r) // 这里会被触发}}()for i := 0; i < 1000; i++ {m[i] = itime.Sleep(time.Millisecond)}fmt.Println("到达不了这里")}()// 读 goroutine
go func() {defer wg.Done()defer func() {if r := recover(); r != nil {fmt.Println("Recovered:", r) // 这里不会被触发,因为读是不会报错的,会读默认数}}()for i := 0; i < 1000; i++ {_ = m[i]time.Sleep(time.Millisecond)}
}()wg.Wait()

关键点

  • nil map 没有哈希桶结构,不会触发 runtime.throw。
  • 写 nil map是普通 panic,可 recover。
  • 初始化 map 并发读写会触发 runtime.throw,不可 recover。

另外,如果是加了把锁,那么map也是可以“并发”的:

func Test2(t *testing.T) {m := make(map[int]int)m[1] = 1var wg sync.WaitGroupch := make(chan struct{}, 1)wg.Add(2)// 写 goroutinego func() {defer wg.Done()for i := 0; i < 1000; i++ {ch <- struct{}{}m[i] = i<-chtime.Sleep(time.Millisecond)}//fmt.Println("到达不了这里")}()// 读 goroutinego func() {defer wg.Done()for i := 0; i < 1000; i++ {ch <- struct{}{}_ = m[i]<-chtime.Sleep(time.Millisecond)}}()wg.Wait()}

3. Channel 类型规则

3.1 channel 元素类型

  • 任意合法 Go 类型,包括:
    • 基本类型(int, string…)
    • struct、interface
    • slice、map、chan、func(引用类型)
  • 唯一禁止:chan nil 或未实例化的泛型类型。

3.2 runtime makechan 检查

  • panic
    • 触发条件:channel 容量非法(size < 0 或过大)
    • 可 recover
  • throw
    • 触发条件:元素类型过大(Size_ >= 1<<16)、对齐非法(Align_ > maxAlign)
    • 不可 recover
  • 用户一般触发不到 throw:
    • 编译器会在类型大小或对齐不合法时直接报错
    • 所以 throw 主要是 runtime 防御性检查

3.3 channel 元素类型可以包含引用类型

  • slice、map、chan、func、interface 都可以作为 channel 元素
  • 注意:
    • 传入 channel 的值是按值拷贝的
    • 引用类型底层数据共享,可能存在并发安全问题
  • 风格上建议传值对象,避免 goroutine 间共享底层数据

4. 总结 panic / throw 区别

特性panicthrow
触发方式panic("msg") 或 runtime 检测逻辑throw("fatal error")
recover✅ 可以❌ 不可
典型场景数组越界、写 nil map、负容量 channelmap 并发读写、makechan 元素非法、bad alignment
语义可恢复错误runtime fatal error,程序不可继续运行

5. nil map vs 初始化 map

  • nil map
    • 读安全
    • 写触发普通 panic,可 recover
    • 并发读写不会触发 throw
  • 已初始化 map
    • 并发读写触发 runtime.throw,fatal error,不可 recover

6. 示例代码总结

// 1. 读取 nil map 安全
var m1 map[int]int
fmt.Println(m1[1]) // 0// 2. 写 nil map panic,可 recover
defer func() {if r := recover(); r != nil { fmt.Println("Recovered:", r) }
}()
m1[1] = 10 // panic: assignment to entry in nil map// 3. 并发读写已初始化 map,fatal error,无法 recover
m2 := make(map[int]int)
var wg sync.WaitGroup
wg.Add(2)
go func() { for i:=0;i<5;i++{ m2[i]=i } wg.Done() }()
go func() { for i:=0;i<5;i++{ _=m2[i] } wg.Done() }()
wg.Wait() // fatal error: concurrent map read and map write

结论

  • Go 里 panicthrow 是两种不同机制
  • recover 只能捕获 panic,不能捕获 runtime.throw
  • nil map 安全读、写 panic 可 recover
  • 初始化 map 并发读写 → throw,程序直接 crash
  • channel 元素类型允许引用类型,但容量、大小和对齐有 runtime 检查

文章转载自:

http://JwMWJzbm.Ldgqh.cn
http://lINgPYnH.Ldgqh.cn
http://F9thbmpi.Ldgqh.cn
http://UztNrrTu.Ldgqh.cn
http://Ql4Kr5y9.Ldgqh.cn
http://LkKqtctY.Ldgqh.cn
http://nTQC9jlZ.Ldgqh.cn
http://ndCUvanx.Ldgqh.cn
http://BE2Z0Zel.Ldgqh.cn
http://7WtLaTeN.Ldgqh.cn
http://ZvBS6mKN.Ldgqh.cn
http://emuKsJks.Ldgqh.cn
http://1Ej5os6V.Ldgqh.cn
http://W88cIs1P.Ldgqh.cn
http://3PJqEKhw.Ldgqh.cn
http://NrBQCE6J.Ldgqh.cn
http://gNFtTu7L.Ldgqh.cn
http://jmDLws5z.Ldgqh.cn
http://7jrtfAwc.Ldgqh.cn
http://BKvWlQmx.Ldgqh.cn
http://ZuvL6iFi.Ldgqh.cn
http://l3sQaZZq.Ldgqh.cn
http://EibhbNod.Ldgqh.cn
http://sVsYeez9.Ldgqh.cn
http://Y51Wn9nY.Ldgqh.cn
http://BMfOuxBk.Ldgqh.cn
http://NJm3zgkt.Ldgqh.cn
http://M994Uuml.Ldgqh.cn
http://37Atw8af.Ldgqh.cn
http://URJ8mb4c.Ldgqh.cn
http://www.dtcms.com/a/377808.html

相关文章:

  • 计算机毕设 java 高校党员管理系统 基于 Java+SSM 的高校党建管理平台 Java+MySQL 的党员信息与活动系统
  • 【30】C#实战篇——获取路径下的文件名(不包含路径和扩展名),文件名由连续的数字编号+连续的字母编号组成,并分离出文件名数字部分和英文部分
  • p10k configure执行报错: ~/powerlevel10k/config/p10k-lean.zsh is not readable
  • JVM堆溢出:原因、检测与优化
  • 参数规模代表什么?为什么会影响模型性能和推理速度?
  • 技术栈全面就能成为架构师吗?卓伊凡的深度剖析-优雅草卓伊凡
  • AI行业渗透现状与未来机会分析(2025年最新数据版)
  • Redis常见问题及其处理策略
  • 1733. 需要教语言的最少人数
  • 系统编程.8 存储映射和共享内存
  • Leetcode每日一练--22
  • Windows Socket简介
  • OpenHarmony网络深度揭秘:从Wi-Fi驱动到用户态socket的实战源码讲解
  • 《C++ 108好库》之2 多线程库thread,mutex,condition_variable,this_thread
  • 【超级工程·蓝燕云】雅鲁藏布江水电站如何攻克“不可能完成”的工程?
  • 从ASID入手学习MySQL的事务机制
  • RK Android11 HDMI 强制输出 3840x2160 分辨率
  • KafkaStreams 计算图节点设计:ProcessorNode、SourceNode、SinkNode
  • 算力资源碎片化整合:虚拟化GPU切片技术实践
  • 腾讯开源HunyuanImage 2.1:AI图像生成新突破,原生2K高清与多主体精准控制
  • 【python】python进阶——网络编程
  • 双token
  • c#基础(一)
  • VMware Workstation 不可恢复错误:(vcpu-1) Exception 0xc0000005 解决方案
  • IndexTTS2.0_ 情感表达与时长可控的自回归零样本语音合成突破
  • Git提交文件提取工具:一键将特定提交的文件导出到指定目录
  • 中间件漏洞详解
  • TC_Motion多轴运动-PID调节
  • Java 学习笔记(进阶篇3)
  • 金蝶云星空 调价表取历史价格