go中異常處理流程

来源:https://www.cnblogs.com/lianshuiwuyi/archive/2023/11/18/17840206.html
-Advertisement-
Play Games

在 Go 語言中,panic、recover 和 defer 是用於處理異常情況的關鍵字。它們通常一起使用來實現對程式錯誤的處理和恢復。 1. defer 語句 defer 用於在函數返回之前執行一段代碼。被 defer 修飾的語句或函數會在包含 defer 的函數執行完畢後執行。defer 常用於 ...


在 Go 語言中,panicrecoverdefer 是用於處理異常情況的關鍵字。它們通常一起使用來實現對程式錯誤的處理和恢復。

1. defer 語句

defer 用於在函數返回之前執行一段代碼。被 defer 修飾的語句或函數會在包含 defer 的函數執行完畢後執行。defer 常用於資源清理、釋放鎖、關閉文件等操作。

func example() {
    defer fmt.Println("This will be executed last")
    fmt.Println("This will be executed first")
}

2. panicrecover

  • 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. 示例

  1. 當程式執行到 panic 語句時,它會立即停止當前函數的執行,並開始沿調用堆棧向上執行所有的 defer 語句。
  2. 執行 defer 語句時,將其推遲的函數或語句加入到一個棧中,但並不立即執行。
  3. 當所有的 defer 語句都被執行完畢後,程式會終止當前的函數執行,然後開始執行上一層函數的 defer 語句,以此類推。
  4. 如果在 defer 語句執行的過程中發生了 panic,則 panic 會被引發,但是在引發 panic 之前,會先執行該層級的 defer 語句。
  5. 如果有 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運行時會按照以下步驟進行處理:

  1. 異常的傳播:當一個函數發生panic時,該函數會立即停止執行,並將panic傳播到調用它的函數。這個過程會一直向上傳播,直到被捕獲或程式終止。
  2. 棧的展開(Unwinding):在panic發生時,Go運行時會開始展開調用棧(stack unwinding)。這意味著它會逆序執行當前調用棧中的函數,直到找到一個能夠處理panic的函數。
  3. 恢復(Recovery):在展開調用棧的過程中,Go運行時會尋找一個適當的recover函數來捕獲並處理panicrecover函數是在當前協程的上下文中執行的,用於捕獲並處理當前協程中的panic。如果找到了一個recover函數,並且它成功處理了panic(即沒有再次觸發panic),則程式會從發生panic的位置開始繼續執行。
  4. 如果沒有找到適當的recover函數來處理panic,程式將終止執行,並列印出相應的錯誤信息。

在處理panic時,需要註意以下幾點:

  • panic通常表示程式中存在無法恢復的錯誤,因此應該儘量避免在正常的程式邏輯中使用panic
  • panicrecover是用於處理程式中的異常情況,而不是用於控製程序的正常流程。
  • recover函數只能在協程(goroutine)的執行過程中使用,並且只能捕獲當前協程中的panic
  • 當一個協程出現panic時,其它協程不會受到影響,會繼續獨立執行。

孟斯特

聲明:本作品採用署名-非商業性使用-相同方式共用 4.0 國際 (CC BY-NC-SA 4.0)進行許可,使用時請註明出處。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 戀水無意
騰訊雲開發者社區:孟斯特



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 寫在前面 筆者技術真的很一般,也許只靠著笨鳥先飛的這種傻瓜堅持,才能在互聯網行業僥幸的生存下來吧! 為什麼這麼說? 我曾不止一次在某群,看到說我寫的東西一點技術含量都沒有,而且很沒營養,換作一年前的我,也許會懟回去,現在的話,我只是看到了,完事忘記了。 早期寫文章是為了當筆記用,不會隨時查閱,當然也 ...
  • 如圖: 已知圖片中標註1、2、3對應的內容 在業務中我需要獲取標誌2對應的"58"這個值,但是這個值不包括在某個標簽中,在span“集數”和br標簽之間,為了減小獲取"58"這個值不被之前的標簽數量的影響 先獲取標簽1所對應的元素,因為標簽1有property="v:initialReleaseDa ...
  • 題目 基礎結構體練習: 創建一個名為Person的結構體,包含name(字元串類型)和age(整數類型)兩個欄位。 寫一個函數,接收一個Person實例作為參數,並列印出這個人的名字和年齡。 結構體方法練習: 為Person結構體添加一個方法birthday,當調用時,它將這個人的年齡增加1。 創建 ...
  • trait是什麼? Rust中的trait是一種定義可被多種類型實現的共用行為的方式。它類似於Java或C#中的介面。通過trait,你可以定義一組方法簽名(有時包括預設實現),不同的類型可以實現這些方法。這有助於抽象通用功能並確保不同類型間一定程度的一致性。 當一個類型實現了一個trait,它承諾 ...
  • 要知道經典類和新式類的區別,首先要掌握類的繼承 類的繼承的一個優點就是減少代碼冗餘 廣度優先和深度優先,這主要是在多類繼承的時候會使用到 經典類和新式類的主要區別就是類的繼承的方式 經典類遵循深度優先的規則,新式類遵循廣度優先的規則。 至於什麼是深度優先什麼是廣度優先,可以看如下示例: class ...
  • 1.輸入日期,判斷這一天是這一年的第幾天 import datetime def day_of_year(): year = eval(input('請輸入年份:')) month = eval(input('請輸入月份:')) day = eval(input('請輸入天:')) date1 = ...
  • 最近天氣降溫厲害,咱們用Python來分析一下空氣質量如何~ 話不多說,我們直接開始上手。 環境以及模塊 環境使用 Python 3.8 Pycharm nodejs 模塊使用 import requests import execjs import json requests和execjs 都是第 ...
  • Windows Management Instrumentation(WMI)是一種用於管理和監視`Windows`操作系統的框架。它為開發人員、系統管理員和自動化工具提供了一種標準的介面,通過這個介面,可以獲取有關電腦系統硬體、操作系統和應用程式的信息,以及對系統進行管理和控制的能力。WQL 的... ...
一周排行
    -Advertisement-
    Play Games
  • 1、預覽地址:http://139.155.137.144:9012 2、qq群:801913255 一、前言 隨著網路的發展,企業對於信息系統數據的保密工作愈發重視,不同身份、角色對於數據的訪問許可權都應該大相徑庭。 列如 1、不同登錄人員對一個數據列表的可見度是不一樣的,如數據列、數據行、數據按鈕 ...
  • 前言 上一篇文章寫瞭如何使用RabbitMQ做個簡單的發送郵件項目,然後評論也是比較多,也是準備去學習一下如何確保RabbitMQ的消息可靠性,但是由於時間原因,先來說說設計模式中的簡單工廠模式吧! 在瞭解簡單工廠模式之前,我們要知道C#是一款面向對象的高級程式語言。它有3大特性,封裝、繼承、多態。 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 介紹 Nodify是一個WPF基於節點的編輯器控制項,其中包含一系列節點、連接和連接器組件,旨在簡化構建基於節點的工具的過程 ...
  • 創建一個webapi項目做測試使用。 創建新控制器,搭建一個基礎框架,包括獲取當天日期、wiki的請求地址等 創建一個Http請求幫助類以及方法,用於獲取指定URL的信息 使用http請求訪問指定url,先運行一下,看看返回的內容。內容如圖右邊所示,實際上是一個Json數據。我們主要解析 大事記 部 ...
  • 最近在不少自媒體上看到有關.NET與C#的資訊與評價,感覺大家對.NET與C#還是不太瞭解,尤其是對2016年6月發佈的跨平臺.NET Core 1.0,更是知之甚少。在考慮一番之後,還是決定寫點東西總結一下,也回顧一下.NET的發展歷史。 首先,你沒看錯,.NET是跨平臺的,可以在Windows、 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 添加節點(nodes) 通過上一篇我們已經創建好了編輯器實例現在我們為編輯器添加一個節點 添加model和viewmode ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...
  • 類型檢查和轉換:當你需要檢查對象是否為特定類型,並且希望在同一時間內將其轉換為那個類型時,模式匹配提供了一種更簡潔的方式來完成這一任務,避免了使用傳統的as和is操作符後還需要進行額外的null檢查。 複雜條件邏輯:在處理複雜的條件邏輯時,特別是涉及到多個條件和類型的情況下,使用模式匹配可以使代碼更 ...
  • 在日常開發中,我們經常需要和文件打交道,特別是桌面開發,有時候就會需要載入大批量的文件,而且可能還會存在部分文件缺失的情況,那麼如何才能快速的判斷文件是否存在呢?如果處理不當的,且文件數量比較多的時候,可能會造成卡頓等情況,進而影響程式的使用體驗。今天就以一個簡單的小例子,簡述兩種不同的判斷文件是否... ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...