最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言Goroutines?泄漏場景與防治解決分析

 更新時間:2022年12月15日 09:44:38   作者:小馬別過河  
這篇文章主要為大家介紹了Go語言Goroutines?泄漏場景與防治解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

場景

Go 有很多自動管理內存的功能。比如:

  • 變量分配到堆內存還是棧內存,編譯器會通過逃逸分析(escpage analysis)來判斷;
  • 堆內存的垃圾自動回收。

即便如此,如果編碼不謹慎,我們還是有可能導致內存泄漏的,最常見的是 goroutine 泄漏,比如下面的函數:

func goroutinueLeak() {
	ch := make(chan int)
	go func(ch chan int) {
    // 因為 ch 一直沒有數據,所以這個協程會阻塞在這里。
		val := <-ch
		fmt.Println(val)
	}(ch)
}

由于ch一直沒有發(fā)送數據,所以我們開啟的 goroutine 會一直阻塞。每次調用goroutinueLeak都會泄漏一個goroutine,從監(jiān)控面板看到話,goroutinue 數量會逐步上升,直至服務 OOM。

Goroutine 泄漏常見原因

channel 發(fā)送端導致阻塞

使用 context 設置超時是常見的一個場景,試想一下,下面的函數什么情況下會 goroutine 泄漏 ?

func contextLeak() error {
	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
	defer cancel()
	ch := make(chan int)
        //g1
	go func() {
		// 獲取數據,比如網絡請求,可能時間很久
		val := RetriveData()
		ch <- val
	}()
	select {
	case <-ctx.Done():
		return errors.New("timeout")
	case val := <-ch:
		fmt.Println(val)
	}
	return nil
}

RetriveData() 如果超時了,那么contextLeak() 會返回 error,本函數執(zhí)行結束。而我們開啟的協程g1,由于沒有接受者,會阻塞在 ch<-val。

解決方法也能簡單,比如可以給ch加上緩存。

channel 接收端導致阻塞

開篇給出的函數goroutinueLeak,就是因為channel的接收端收不到數據,導致阻塞。

這里舉出另一個例子,下面的函數,是否有可能 goroutinue 泄漏?

func errorAssertionLeak() {
	ch := make(chan int)
        // g1
	go func() {
		val := <-ch
		fmt.Println(val)
	}()
        // RetriveSomeData 表示獲取數據,比如從網絡上
	val, err := RetriveSomeData()
	if err != nil {
		return
	}
	ch <- val
	return nil
}

如果 RetriveSomeData() 返回的err 不為 nil,那么本函數中斷,也就不會有數據發(fā)送給ch,這導致協程g1會一直阻塞。

如何預防

goroutine 泄漏往往需要服務運行一段時間后,才會被發(fā)覺。

我們可以通過監(jiān)控 goroutine 數量來判斷是否有 goroutine 泄漏;或者用 pprof(之前文章介紹過的) 來定位泄漏的 goroutine。但這些已經是亡羊補牢了。最理想的情況是,我們在開發(fā)的過程中,就能發(fā)現。

本文推薦的做法是,使用單元測試。以開篇的 goroutinueLeak 為例子,我們寫個單測:

func TestLeak(t *testing.T) {
	goroutinueLeak()
}

執(zhí)行 go test,發(fā)現測試是通過的:

=== RUN   TestLeak
--- PASS: TestLeak (0.00s)
PASS
ok      example/leak    0.598s

這是是因為單測默認不會檢測 goroutine 泄漏的。

我們可以在單測中,加入Uber 團隊提供的 uber-go/goleak 包:

import (
	"testing"
	"go.uber.org/goleak"
)
func TestLeak(t *testing.T) {
        // 加上這行代碼,就會自動檢測是否 goroutine 泄漏
	defer goleak.VerifyNone(t)
	goroutinueLeak()
}

這時候執(zhí)行 go test,輸出:

=== RUN   TestLeak
    /xxx/leak_test.go:12: found unexpected goroutines:
        [Goroutine 21 in state chan receive, with example/leak.goroutinueLeak.func1 on top of the stack:
        goroutine 21 [chan receive]:
        example/leak.goroutinueLeak.func1(0x0)
            /xxx/leak.go:9 +0x27
        created by example/leak.goroutinueLeak
            /xxx/leak.go:8 +0x7a
        ]
--- FAIL: TestLeak (0.46s)
FAIL
FAIL    example/leak    0.784s

這時候單測會因為 goroutine 泄漏而不通過。

如果你覺得每個測試用例都要加上 defer goleak.VerifyNone(t) 太繁瑣的話(特別是在已有的項目中加上),goleak 提供了在 TestMain 中使用的方法VerifyTestMain,上面的單測可以修改成:

func TestLeak(t *testing.T) {
	goroutinueLeak()
}
func TestMain(m *testing.M) {
	goleak.VerifyTestMain(m)
}

總結

雖然我的文章經常提及單測,但我本人不是單元測試的忠實粉絲。扎實的基礎,充分的測試,負責任的態(tài)度也是非常重要的。

引用

以上就是Go語言Goroutines 泄漏場景與防治解決分析的詳細內容,更多關于Go Goroutines 泄漏防治的資料請關注腳本之家其它相關文章!

相關文章

  • Goland字符串格式化樣式中“\r“的作用詳解

    Goland字符串格式化樣式中“\r“的作用詳解

    這篇文章主要介紹了Goland字符串格式化樣式中“\r“的作用,"\r"起的作用是回到行首,當前控制臺輸出,輸出完以后回到當前行的行首,本文給大家介紹的非常詳細,需要的朋友可以參考下
    2023-04-04
  • 使用Golang編寫一個簡單的命令行工具

    使用Golang編寫一個簡單的命令行工具

    Cobra是一個強大的開源工具,能夠幫助我們快速構建出優(yōu)雅且功能豐富的命令行應用,本文將利用Cobra編寫一個簡單的命令行工具,感興趣的可以了解下
    2023-12-12
  • Golang中時間戳與時區(qū)轉換的方法詳解

    Golang中時間戳與時區(qū)轉換的方法詳解

    時間是我們生活的基石,而在計算機科學中,時間處理顯得尤為重要,尤其是當你在處理分布式系統、跨時區(qū)應用和全球服務時,時間和時區(qū)的管理變得不可或缺,在這篇文章中,我們將深入探討Golang中的時間戳與時區(qū)轉換,需要的朋友可以參考下
    2024-06-06
  • Go語言中的延遲函數defer示例詳解

    Go語言中的延遲函數defer示例詳解

    眾所周知golang的defer優(yōu)雅又簡潔, 是golang的亮點之一。所以下面這篇文章主要給大家介紹了關于Go語言中延遲函數defer的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧。
    2017-10-10
  • go語言開發(fā)環(huán)境配置(sublime text3+gosublime)

    go語言開發(fā)環(huán)境配置(sublime text3+gosublime)

    網上google了下go的開發(fā)工具,大都推薦sublime text3+gosublime,本文就介紹了go語言開發(fā)環(huán)境配置(sublime text3+gosublime),具有一定的參考價值,感興趣的可以了解一下
    2022-01-01
  • 淺談go語言中別名類型的使用

    淺談go語言中別名類型的使用

    類型別名是 Go 1.9 版本添加的新功能,主要用于解決代碼升級、遷移中存在的類型兼容性問題,本文主要介紹了go語言中別名類型的使用,感興趣的可以了解一下
    2024-01-01
  • golang編程入門之http請求天氣實例

    golang編程入門之http請求天氣實例

    這篇文章主要介紹了golang編程入門之http請求天氣實例,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • go集成gorm數據庫的操作代碼

    go集成gorm數據庫的操作代碼

    GORM 是一個用于 Go 語言的 ORM(對象關系映射)庫,它提供了一種簡單而強大的方式來與數據庫進行交互,GORM 支持多種數據庫,并且提供了豐富的功能,如自動遷移、預加載、事務管理等,文中通過代碼示例講解的非常詳細,需要的朋友可以參考下
    2024-11-11
  • Golang?WaitGroup?底層原理及源碼解析

    Golang?WaitGroup?底層原理及源碼解析

    WaitGroup?是?Golang?中最常見的并發(fā)控制技術之一,它的作用我們可以簡單類比為其他語言中多線程并發(fā)控制中的?join(),這篇文章主要介紹了Golang?WaitGroup?底層原理及源碼詳解,需要的朋友可以參考下
    2023-04-04
  • go使用makefile腳本編譯應用的方法小結

    go使用makefile腳本編譯應用的方法小結

    makefile可以看作是make工具的腳本文件, 而make主要用來處理一系列命令。常用的比如用來編譯和打包文件, 在C/C++的編譯打包中應用最廣泛了,這篇文章主要介紹了go使用makefile腳本編譯應用,需要的朋友可以參考下
    2022-08-08

最新評論

大田县| 泗洪县| 石嘴山市| 银川市| 达日县| 涟水县| 靖江市| 沈丘县| 北京市| 江达县| 巴马| 清丰县| 子长县| 得荣县| 平泉县| 栾川县| 阜宁县| 图木舒克市| 黄冈市| 斗六市| 晋州市| 昆山市| 鹤山市| 武胜县| 萨嘎县| 新巴尔虎右旗| 彰武县| 应城市| 新泰市| 洛阳市| 岳阳县| 东阿县| 突泉县| 会东县| 安阳县| 彰化县| 巴南区| 六安市| 大关县| 大洼县| 蕉岭县|