线程安全和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.Mutexfunc 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("正常逻辑代码")}deferruntime 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])}deferruntime error: index out of range [3] with length 2goroutine 1 [running]:runtime/debug.Stack() D:/Program Files/go1.25.5.windows-amd64/go/src/runtime/debug/stack.go:26 +0x5emain.read.func1() D:/project/go_study/study/21.异常处理/3.异常捕获.go:15 +0x8apanic({0x7ff760bac060?, 0xc0000140d8?}) D:/Program Files/go1.25.5.windows-amd64/go/src/runtime/panic.go:783 +0x132main.read() D:/project/go_study/study/21.异常处理/3.异常捕获.go:19 +0x3amain.main() D:/project/go_study/study/21.异常处理/3.异常捕获.go:23 +0x13
正常逻辑代码这个用于捕获异常的defer的延迟函数可以在调用链路上的任何一个函数上
一般用于在最上层函数,捕获所有异常



