日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁(yè) > 科技  > 軟件

常見的 Goroutine 泄露,你應(yīng)該避免

來(lái)源: 責(zé)編: 時(shí)間:2023-10-29 21:44:59 295觀看
導(dǎo)讀Go 語(yǔ)言編寫代碼的最大優(yōu)點(diǎn)之一是能夠在輕量級(jí)線程,即 Goroutines 中并發(fā)運(yùn)行你的代碼。然而,擁有強(qiáng)大的能力也伴隨著巨大的責(zé)任。盡管 Goroutines 非常方便,但如果不小心處理,它們很容易引入難以追蹤的錯(cuò)誤。Goroutine

Go 語(yǔ)言編寫代碼的最大優(yōu)點(diǎn)之一是能夠在輕量級(jí)線程,即 Goroutines 中并發(fā)運(yùn)行你的代碼。w5a28資訊網(wǎng)——每日最新資訊28at.com

然而,擁有強(qiáng)大的能力也伴隨著巨大的責(zé)任。w5a28資訊網(wǎng)——每日最新資訊28at.com

盡管 Goroutines 非常方便,但如果不小心處理,它們很容易引入難以追蹤的錯(cuò)誤。w5a28資訊網(wǎng)——每日最新資訊28at.com

Goroutine 泄露就是其中之一。它在背景中悄悄增長(zhǎng),可能最終在你不知情的情況下使你的應(yīng)用程序崩潰。w5a28資訊網(wǎng)——每日最新資訊28at.com

因此,本文主要介紹 Goroutine 泄露是什么,以及你如何防止泄露發(fā)生。w5a28資訊網(wǎng)——每日最新資訊28at.com

我們來(lái)看看吧!w5a28資訊網(wǎng)——每日最新資訊28at.com

w5a28資訊網(wǎng)——每日最新資訊28at.com

什么是 Goroutine 泄露?

當(dāng)創(chuàng)建一個(gè)新的 Goroutine 時(shí),計(jì)算機(jī)在堆中分配內(nèi)存,并在執(zhí)行完成后釋放它們。w5a28資訊網(wǎng)——每日最新資訊28at.com

Goroutine 泄露是一種內(nèi)存泄露,當(dāng) Goroutine 沒有終止并在應(yīng)用程序的生命周期中被留在后臺(tái)時(shí)就會(huì)發(fā)生。w5a28資訊網(wǎng)——每日最新資訊28at.com

讓我們來(lái)看一個(gè)簡(jiǎn)單的例子。w5a28資訊網(wǎng)——每日最新資訊28at.com

func goroutineLeak(ch chan int) {    data := <- ch    fmt.Println(data)}func handler() {    ch := make(chan int)        go goroutineLeak(ch)    return}

隨著處理器的返回,Goroutine 繼續(xù)在后臺(tái)活動(dòng),阻塞并等待數(shù)據(jù)通過(guò)通道發(fā)送 —— 這永遠(yuǎn)不會(huì)發(fā)生。w5a28資訊網(wǎng)——每日最新資訊28at.com

因此,產(chǎn)生了一個(gè) Goroutine 泄露。w5a28資訊網(wǎng)——每日最新資訊28at.com

在本文中,我將引導(dǎo)你了解兩種常見的模式,這些模式很容易導(dǎo)致 Goroutine 泄漏:w5a28資訊網(wǎng)——每日最新資訊28at.com

  • 遺忘的發(fā)送者
  • 被遺棄的接收者

讓我們深入研究!w5a28資訊網(wǎng)——每日最新資訊28at.com

遺忘的發(fā)送者

遺忘的發(fā)送者發(fā)生在發(fā)送者被阻塞,因?yàn)闆]有接收者在通道的另一側(cè)等待接收數(shù)據(jù)的情況。w5a28資訊網(wǎng)——每日最新資訊28at.com

func forgottenSender(ch chan int) {    data := 3      // This is blocked as no one is receiving the data    ch <- data}func handler () {    ch := make(chan int)      go forgottenSender(ch)    return}

雖然它起初看起來(lái)很簡(jiǎn)單,但在以下兩種情境中很容易被忽視。w5a28資訊網(wǎng)——每日最新資訊28at.com

不當(dāng)使用 Context

func forgottenSender(ch chan int) {    data := networkCall()      ch <- data}func handler() error {    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)    defer cancel()      ch := make(chan int)    go forgottenSender(ch)      select {        case data := <- ch: {            fmt.Printf("Received data! %s", data)                  return nil        }            case <- ctx.Done(): {            return errors.New("Timeout! Process cancelled. Returning")        }    }}

在上面的例子中,我們模擬了一個(gè)標(biāo)準(zhǔn)的網(wǎng)絡(luò)服務(wù)處理程序。w5a28資訊網(wǎng)——每日最新資訊28at.com

我們定義了一個(gè)上下文,它在10ms后發(fā)出超時(shí),隨后是一個(gè)異步進(jìn)行網(wǎng)絡(luò)調(diào)用的Goroutine。w5a28資訊網(wǎng)——每日最新資訊28at.com

select語(yǔ)句等待多個(gè)通道操作。它會(huì)阻塞,直到其其中一個(gè)情況可以運(yùn)行并執(zhí)行該情況。w5a28資訊網(wǎng)——每日最新資訊28at.com

如果網(wǎng)絡(luò)調(diào)用完成之前超時(shí)到達(dá),case <- ctx.Done() 將會(huì)執(zhí)行,處理程序?qū)⒎祷匾粋€(gè)錯(cuò)誤。w5a28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)處理程序返回時(shí),不再有任何接收者等待接收數(shù)據(jù)。forgottenSender將被阻塞,等待有人接收數(shù)據(jù),但這永遠(yuǎn)不會(huì)發(fā)生!w5a28資訊網(wǎng)——每日最新資訊28at.com

這就是Goroutine泄露的地方。w5a28資訊網(wǎng)——每日最新資訊28at.com

錯(cuò)誤檢查后的接收者位置

這是另一個(gè)典型的情況。w5a28資訊網(wǎng)——每日最新資訊28at.com

func forgottenSender(ch chan int) {    data := networkCall()      ch <- data}func handler() error {    ch := make(chan int)    go forgottenSender(ch)      err := continueToValidateOtherData()    if err != nil {        return errors.New("Data is invalid! Returning.")    }      data := <- ch      return nil}

在上面的例子中,我們定義了一個(gè)處理程序并生成一個(gè)新的Goroutine來(lái)異步進(jìn)行網(wǎng)絡(luò)調(diào)用。w5a28資訊網(wǎng)——每日最新資訊28at.com

在等待調(diào)用返回的過(guò)程中,我們繼續(xù)其他的驗(yàn)證邏輯。w5a28資訊網(wǎng)——每日最新資訊28at.com

如你所見,當(dāng)continueToValidateOtherData返回一個(gè)錯(cuò)誤導(dǎo)致處理程序返回時(shí),泄露就發(fā)生了。w5a28資訊網(wǎng)——每日最新資訊28at.com

沒有人等待接收數(shù)據(jù),forgottenSender將永遠(yuǎn)被阻塞!w5a28資訊網(wǎng)——每日最新資訊28at.com

解決方案:忘記的發(fā)送者

使用一個(gè)緩沖通道。w5a28資訊網(wǎng)——每日最新資訊28at.com

如果你回想一下,忘記的發(fā)送者發(fā)生是因?yàn)榱硪欢藳]有接收者。阻塞問(wèn)題的罪魁禍?zhǔn)资且粋€(gè)無(wú)緩沖的通道!w5a28資訊網(wǎng)——每日最新資訊28at.com

一個(gè)無(wú)緩沖的通道是在消息發(fā)出時(shí)立即需要一個(gè)接收者的,否則發(fā)送者會(huì)被阻塞。它是在沒有為通道分配容量的情況下聲明的。w5a28資訊網(wǎng)——每日最新資訊28at.com

func forgottenSender(ch chan int) {    data := 3      // This will NOT block    ch <- data}func handler() {    // Declare a BUFFERED channel    ch := make(chan int, 1)      go forgottenSender(ch)    return}

通過(guò)為通道添加特定的容量,在這種情況下為1,我們可以減少所有提到的問(wèn)題。w5a28資訊網(wǎng)——每日最新資訊28at.com

發(fā)送者可以在不需要接收者的情況下將數(shù)據(jù)注入通道。w5a28資訊網(wǎng)——每日最新資訊28at.com

被遺棄的接收者

正如其名字所暗示的,被遺棄的接收者是完全相反的情況。w5a28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)一個(gè)接收者被阻塞,因?yàn)榱硪贿厸]有發(fā)送者發(fā)送數(shù)據(jù)時(shí),它就會(huì)發(fā)生。w5a28資訊網(wǎng)——每日最新資訊28at.com

func abandonedReceiver(ch chan int) {    // This will be blocked    data := <- ch      fmt.Println(data) }func handler() {    ch := make(chan int)      go abandonedReceiver(ch)      return}

第3行一直被阻塞,因?yàn)闆]有發(fā)送者發(fā)送數(shù)據(jù)。w5a28資訊網(wǎng)——每日最新資訊28at.com

讓我們?cè)俅瘟私鈨蓚€(gè)常見的場(chǎng)景,這些場(chǎng)景經(jīng)常被忽視。w5a28資訊網(wǎng)——每日最新資訊28at.com

發(fā)送者未關(guān)閉的通道

func abandonedWorker(ch chan string) {    for data := range ch {        processData(data)    }      fmt.Println("Worker is done, shutting down")}func handler(inputData []string) {    ch := make(chan string, len(inputData))      for _, data := range inputData {        ch <- data    }      go abandonedWorker(ch)        return}

在上面的例子中,處理程序接收一個(gè)字符串切片,創(chuàng)建一個(gè)通道并將數(shù)據(jù)插入到通道中。w5a28資訊網(wǎng)——每日最新資訊28at.com

處理程序然后通過(guò)Goroutine啟動(dòng)一個(gè)工作程序。工作程序預(yù)計(jì)會(huì)處理數(shù)據(jù),并且一旦處理完通道中的所有數(shù)據(jù),就會(huì)終止。w5a28資訊網(wǎng)——每日最新資訊28at.com

然而,即使消耗并處理了所有的數(shù)據(jù),工作程序也永遠(yuǎn)不會(huì)到達(dá)“第6行”!w5a28資訊網(wǎng)——每日最新資訊28at.com

盡管通道是空的,但它沒有被關(guān)閉!工作程序繼續(xù)認(rèn)為未來(lái)可能會(huì)有傳入的數(shù)據(jù)。因此,它坐下來(lái)并永遠(yuǎn)等待。w5a28資訊網(wǎng)——每日最新資訊28at.com

這是Goroutine再次泄漏的地方。w5a28資訊網(wǎng)——每日最新資訊28at.com

在錯(cuò)誤檢查之后放置發(fā)送者

這與我們之前的一些示例非常相似。w5a28資訊網(wǎng)——每日最新資訊28at.com

func abandonedWorker(ch chan []int) {    data := <- ch    fmt.Println(data)}func handler() error {    ch := make(chan []int)    go abandonedWorker(ch)    records, err := getFromDB()    if err != nil {        return errors.New("Database error. Returning")    }    ch <- records    return nil}

在上面的例子中,處理程序首先啟動(dòng)一個(gè)Goroutine工作程序來(lái)處理和消費(fèi)一些數(shù)據(jù)。w5a28資訊網(wǎng)——每日最新資訊28at.com

然后,處理程序從數(shù)據(jù)庫(kù)中查詢記錄,然后將記錄注入通道供工作程序使用。w5a28資訊網(wǎng)——每日最新資訊28at.com

如果數(shù)據(jù)庫(kù)出現(xiàn)錯(cuò)誤,處理程序?qū)⒘⒓捶祷亍Mǖ缹⒉辉儆腥魏伟l(fā)送者傳入數(shù)據(jù)。w5a28資訊網(wǎng)——每日最新資訊28at.com

因此,工作程序被遺棄。w5a28資訊網(wǎng)——每日最新資訊28at.com

解決方案:被遺棄的接收者

在這兩種情況下,接收者都被留下,因?yàn)樗麄儭罢J(rèn)為”通道將有傳入的數(shù)據(jù)。因此,它們阻塞并永遠(yuǎn)等待。w5a28資訊網(wǎng)——每日最新資訊28at.com

解決方案是一個(gè)簡(jiǎn)單的單行代碼。w5a28資訊網(wǎng)——每日最新資訊28at.com

defer close(ch)

當(dāng)你啟動(dòng)一個(gè)新的通道時(shí),最好的做法是推遲關(guān)閉通道。w5a28資訊網(wǎng)——每日最新資訊28at.com

這確保在數(shù)據(jù)發(fā)送完成或函數(shù)退出時(shí)關(guān)閉通道。w5a28資訊網(wǎng)——每日最新資訊28at.com

接收者可以判斷一個(gè)通道是否已關(guān)閉,并相應(yīng)地終止。w5a28資訊網(wǎng)——每日最新資訊28at.com

func abandonedReceiver(ch chan int) {    // This will NOT be blocked FOREVER    data := <- ch      fmt.Println(data) }func handler() {    ch := make(chan int)        // Defer the CLOSING of channel    defer close(ch)      go abandonedReceiver(ch)    return}

結(jié)論

關(guān)于 Goroutine 泄漏就是這么多了!w5a28資訊網(wǎng)——每日最新資訊28at.com

盡管它不像其他 Goroutine 錯(cuò)誤那么強(qiáng)大,但這種泄漏仍然會(huì)大大耗盡應(yīng)用程序的內(nèi)存使用。w5a28資訊網(wǎng)——每日最新資訊28at.com

記住,擁有強(qiáng)大的力量也伴隨著巨大的責(zé)任。w5a28資訊網(wǎng)——每日最新資訊28at.com

保護(hù)我們的應(yīng)用程序免受錯(cuò)誤的責(zé)任在于你我——開發(fā)人員!w5a28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-15597-0.html常見的 Goroutine 泄露,你應(yīng)該避免

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 并發(fā)編程:你真的能回答好AQS嗎(補(bǔ)充中斷機(jī)制)

下一篇: Python自動(dòng)查重:原理、方法與實(shí)踐

標(biāo)簽:
  • 熱門焦點(diǎn)
Top 主站蜘蛛池模板: 黄浦区| 抚顺市| 右玉县| 天水市| 珠海市| 普格县| 许昌市| 分宜县| 和硕县| 新宁县| 永吉县| 大渡口区| 上犹县| 德格县| 邵武市| 额敏县| 军事| 通山县| 富顺县| 乐亭县| 原阳县| 元谋县| 六盘水市| 临漳县| 雷山县| 潼南县| 奉节县| 安西县| 勐海县| 颍上县| 阜新市| 桃园市| 儋州市| 临颍县| 安塞县| 龙江县| 濉溪县| 安龙县| 定州市| 兴城市| 建宁县|