种地 发表于 2023-12-30 00:49:50

go中异常处理流程

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

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


[*]panic 用于引发运行时错误,导致程序崩溃。
[*]recover 用于捕获 panic 引发的错误,并进行处理。
func example() {
    defer func() {
      if err := recover(); err != nil {
            fmt.Println("Recovered from panic:", err)
      }
    }()

    panic("This will cause a panic")
}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 不会影响其他协程:
package main

import (
        "fmt"
        "sync"
        "time"
)

func main() {
        var wg sync.WaitGroup

        wg.Add(1)
        go func() {
                defer wg.Done()
                panicExample()
        }()

        // 启动另一个协程
        wg.Add(1)
        go func() {
                defer wg.Done()
                fmt.Println("Another goroutine is running.")
        }()

        // 等待所有协程结束
        wg.Wait()
}

func panicExample() {
        defer func() {
                if r := recover(); r != nil {
                        fmt.Println("Recovered from panic:", r)
                }
        }()

        fmt.Println("Start of panicExample")
        time.Sleep(1 * time.Second)
        panic("Something went wrong!")
        fmt.Println("End of panicExample") // 不会执行到这里
}在这个例子中,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时,其它协程不会受到影响,会继续独立执行。
https://img2023.cnblogs.com/blog/1007709/202308/1007709-20230810162948167-1526955652.jpg声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 恋水无意
腾讯云开发者社区:孟斯特

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: go中异常处理流程