go中异常处理流程

种地  金牌会员 | 2023-12-30 00:49:50 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 554|帖子 554|积分 1662

在 Go 语言中,panic、recover 和 defer 是用于处理异常情况的关键字。它们通常一起使用来实现对程序错误的处理和恢复。
1. defer 语句

defer 用于在函数返回之前执行一段代码。被 defer 修饰的语句或函数会在包含 defer 的函数执行完毕后执行。defer 常用于资源清理、释放锁、关闭文件等操作。
  1. func example() {
  2.     defer fmt.Println("This will be executed last")
  3.     fmt.Println("This will be executed first")
  4. }
复制代码
2. panic 和 recover


  • panic 用于引发运行时错误,导致程序崩溃。
  • recover 用于捕获 panic 引发的错误,并进行处理。
  1. func example() {
  2.     defer func() {
  3.         if err := recover(); err != nil {
  4.             fmt.Println("Recovered from panic:", err)
  5.         }
  6.     }()
  7.     panic("This will cause a panic")
  8. }
复制代码
3. 示例


  • 当程序执行到 panic 语句时,它会立即停止当前函数的执行,并开始沿调用堆栈向上执行所有的 defer 语句。
  • 执行 defer 语句时,将其推迟的函数或语句加入到一个栈中,但并不立即执行。
  • 当所有的 defer 语句都被执行完毕后,程序会终止当前的函数执行,然后开始执行上一层函数的 defer 语句,以此类推。
  • 如果在 defer 语句执行的过程中发生了 panic,则 panic 会被引发,但是在引发 panic 之前,会先执行该层级的 defer 语句。
  • 如果有 recover 函数被调用,它会停止 panic 的传播,并返回传递给 panic 的值。
在 Go 中,一个协程(goroutine)出现 panic 不会直接影响其他协程的正常执行。Go 语言的设计目标之一是实现轻量级的并发,保持协程的独立性。因此,一个协程的 panic 不会波及到其他协程。
当一个协程发生 panic 时,通常会触发一系列的 defer 函数的执行,这提供了一种清理资源或记录日志等操作的机制。然后,Go 运行时系统会停止当前协程的执行,但不会影响其他正在运行的协程。
其他协程会继续执行,而不受 panic 影响。这是由于 Go 使用了处理异常的机制,而不是像传统的错误处理机制那样需要在每个函数中检查错误。在 Go 中,panic 主要用于表示程序遇到无法继续执行的错误情况。
下面是一个简单的例子,演示了一个协程的 panic 不会影响其他协程:
  1. package main
  2. import (
  3.         "fmt"
  4.         "sync"
  5.         "time"
  6. )
  7. func main() {
  8.         var wg sync.WaitGroup
  9.         wg.Add(1)
  10.         go func() {
  11.                 defer wg.Done()
  12.                 panicExample()
  13.         }()
  14.         // 启动另一个协程
  15.         wg.Add(1)
  16.         go func() {
  17.                 defer wg.Done()
  18.                 fmt.Println("Another goroutine is running.")
  19.         }()
  20.         // 等待所有协程结束
  21.         wg.Wait()
  22. }
  23. func panicExample() {
  24.         defer func() {
  25.                 if r := recover(); r != nil {
  26.                         fmt.Println("Recovered from panic:", r)
  27.                 }
  28.         }()
  29.         fmt.Println("Start of panicExample")
  30.         time.Sleep(1 * time.Second)
  31.         panic("Something went wrong!")
  32.         fmt.Println("End of panicExample") // 不会执行到这里
  33. }
复制代码
在这个例子中,panicExample 函数中的 panic 不会影响另一个协程的正常执行。虽然一个协程中发生了 panic,但其他协程仍然可以继续执行。
4. 总结

在Go中,runtime包是负责处理Go运行时(runtime)的细节,包括垃圾回收、协程调度等。当出现panic时,runtime包会负责处理这些异常情况。
当程序中出现panic时,Go运行时会按照以下步骤进行处理:

  • 异常的传播:当一个函数发生panic时,该函数会立即停止执行,并将panic传播到调用它的函数。这个过程会一直向上传播,直到被捕获或程序终止。
  • 栈的展开(Unwinding):在panic发生时,Go运行时会开始展开调用栈(stack unwinding)。这意味着它会逆序执行当前调用栈中的函数,直到找到一个能够处理panic的函数。
  • 恢复(Recovery):在展开调用栈的过程中,Go运行时会寻找一个适当的recover函数来捕获并处理panic。recover函数是在当前协程的上下文中执行的,用于捕获并处理当前协程中的panic。如果找到了一个recover函数,并且它成功处理了panic(即没有再次触发panic),则程序会从发生panic的位置开始继续执行。
  • 如果没有找到适当的recover函数来处理panic,程序将终止执行,并打印出相应的错误信息。
在处理panic时,需要注意以下几点:

  • panic通常表示程序中存在无法恢复的错误,因此应该尽量避免在正常的程序逻辑中使用panic。
  • panic和recover是用于处理程序中的异常情况,而不是用于控制程序的正常流程。
  • recover函数只能在协程(goroutine)的执行过程中使用,并且只能捕获当前协程中的panic。
  • 当一个协程出现panic时,其它协程不会受到影响,会继续独立执行。
  
声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 恋水无意
腾讯云开发者社区:孟斯特

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

种地

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表