Golang 学习笔记08-线程安全和异常处理

AI-摘要
Yuan GPT
AI初始化中...
介绍自己 🙈
生成本文简介 👋
推荐相关文章 📖
前往主页 🏠
前往爱发电购买
Golang 学习笔记08-线程安全和异常处理
SEAlencehe线程安全和sync.Map
假设一个加法和一个减法的协程
package main
import (
"fmt"
"sync"
)
var sum int
var wait sync.WaitGroup
func add() {
for i := 0; i < 1000000; i++ {
sum++
}
wait.Done()
}
func sub() {
for i := 0; i < 1000000; i++ {
sum--
}
wait.Done()
}
func main() {
wait.Add(2)
go add()
go sub()
wait.Wait()
fmt.Println(sum)
}
在预想中,输出的sum值应该是0,但实际不是,每次都不同,无法预测
解决方案:
var lock sync.Mutex
func adds() {
lock.Lock()
for i := 0; i < 1000000; i++ {
sums++
}
lock.Unlock()
waits.Done()
}
func subs() {
lock.Lock()
for i := 0; i < 1000000; i++ {
sums--
}
lock.Unlock()
waits.Done()
}
线程不安全的map,同一时刻在执行读和写
package main
import "fmt"
var maps = map[int]string{}
func main() {
go func() {
for {
maps[1] = "张三"
}
}()
go func() {
for {
fmt.Println(maps[1])
}
}()
select {}
}
fatal error: concurrent map read and map write
解决方案
var maps1 = sync.Map{}
func main() {
go func() {
for {
maps1.Store(1, "张三")
}
}()
go func() {
for {
val, ok := maps1.Load(1)
fmt.Println(val, ok)
}
}()
select {}
}
异常处理
常见的异常处理
向上抛:将错误交给上一级处理
一般是用于框架层,有些错误框架层面不能擅做决定,将错误向上抛不失为一个好的办法
中断程序:遇到错误直接停止程序
这种一般是用于初始化,一旦初始化出现错误,程序继续走下去也意义不大了,还不如中断掉
恢复程序:我们可以在一个函数里面,使用一个defer,可以实现对panic的捕获
以至于出现错误不至于让程序直接崩溃
这种一般也是框架层的异常处理所做的
向上抛
package main
import (
"errors"
"fmt"
)
// 底层函数
func div(a, b int) (res int, err error) {
if b == 0 {
err = errors.New("除数不能为0")
return
}
res = a / b
return
}
// 中层函数
func server() (res int, err error) {
res, err = div(10, 0)
if err != nil {
// 把错误向上传递
return
}
// 执行其他的逻辑
res++
res += 2
return
}
func main() {
res, err := server()
if err != nil {
fmt.Println(err)
return
}
fmt.Println(res)
}
中断程序
func init() {
_, err := os.ReadFile("1.txt")
fmt.Println(err)
}
func main() {
fmt.Println("main")
}
open 1.txt: The system cannot find the file specified.
main
以上的情况并没有对错误处理,依然走到了main
两种处理方式:panic(),log.Fatalln("")
func init() {
_, err := os.ReadFile("1.txt")
fmt.Println(err)
if err != nil {
//panic(err)
log.Fatalln("发生错误")
}
}
open 1.txt: The system cannot find the file specified.
2026/02/08 18:43:10 发生错误
func init() {
_, err := os.ReadFile("1.txt")
fmt.Println(err)
if err != nil {
panic("发生错误")
//log.Fatalln("发生错误")
}
}
open 1.txt: The system cannot find the file specified.
panic: 发生错误
goroutine 1 [running]:
main.init.0()
D:/project/go_study/study/21.异常处理/2.中断程序.go:13 +0x8b
异常捕获
如果函数发生错误会导致后面的正常逻辑代码不再继续运行
package main
import "fmt"
func read() {
var list []int = []int{1, 2}
fmt.Println(list[3])
}
func main() {
read()
// 正常的逻辑代码
fmt.Println("正常逻辑代码")
}
panic: runtime error: index out of range [3] with length 2
解决方案:
func read() {
defer func() {
fmt.Println("defer")
err := recover()
if err != nil {
fmt.Println(err)
}
}()
var list []int = []int{1, 2}
fmt.Println(list[3])
}
func main() {
read()
// 正常的逻辑代码
fmt.Println("正常逻辑代码")
}
defer
runtime error: index out of range [3] with length 2
正常逻辑代码
以上的写法会不知道错误的位置
func read() {
defer func() {
fmt.Println("defer")
err := recover()
if err != nil {
fmt.Println(err)
// 调用堆栈
fmt.Println(string(debug.Stack()))
}
}()
var list []int = []int{1, 2}
fmt.Println(list[3])
}
defer
runtime error: index out of range [3] with length 2
goroutine 1 [running]:
runtime/debug.Stack()
D:/Program Files/go1.25.5.windows-amd64/go/src/runtime/debug/stack.go:26 +0x5e
main.read.func1()
D:/project/go_study/study/21.异常处理/3.异常捕获.go:15 +0x8a
panic({0x7ff760bac060?, 0xc0000140d8?})
D:/Program Files/go1.25.5.windows-amd64/go/src/runtime/panic.go:783 +0x132
main.read()
D:/project/go_study/study/21.异常处理/3.异常捕获.go:19 +0x3a
main.main()
D:/project/go_study/study/21.异常处理/3.异常捕获.go:23 +0x13
正常逻辑代码
这个用于捕获异常的defer的延迟函数可以在调用链路上的任何一个函数上
一般用于在最上层函数,捕获所有异常
评论
匿名评论隐私政策
✅ 你无需删除空行,直接评论以获取最佳展示效果

