簡體   English   中英

為什么goroutine泄漏

[英]Why goroutine leaks

我在第30頁閱讀了Twelve Go Best Practices和遭遇以及有趣的例子。

func sendMsg(msg, addr string) error {
    conn, err := net.Dial("tcp", addr)
    if err != nil {
        return err
    }
    defer conn.Close()
    _, err = fmt.Fprint(conn, msg)
    return err
} 

func broadcastMsg(msg string, addrs []string) error {
    errc := make(chan error)
    for _, addr := range addrs {
        go func(addr string) {
            errc <- sendMsg(msg, addr)
            fmt.Println("done")
        }(addr)
    }

    for _ = range addrs {
        if err := <-errc; err != nil {
            return err
        }
    }
    return nil
}

func main() {
    addr := []string{"localhost:8080", "http://google.com"}
    err := broadcastMsg("hi", addr)

    time.Sleep(time.Second)

    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println("everything went fine")
}

程序員提到,這恰好發生在上面的代碼中:

the goroutine is blocked on the chan write
the goroutine holds a reference to the chan
the chan will never be garbage collected

為什么goroutine在這里受阻? 主線程被阻塞,直到它從goroutine接收數據。 在繼續for循環之后。 不?

為什么errc chan永遠不會被垃圾收集? 因為我沒有關閉頻道,完成goroutine后?

我看到的一個問題是goroutines啟動后的broadcastMsg()內部:

for _ = range addrs {
    if err := <-errc; err != nil {
        return err
    }
}

如果一個非nil error是從接收errcbroadcastMsg()與該錯誤立即返回,並且不從通道,這意味着進一步夠程將永遠不會因為暢通接受任何最新值errc是緩沖的。

可能的修復

可能的解決方法是使用緩沖通道,大到足以阻止任何goroutine,在這種情況下:

errc := make(chan error, len(addrs))

或者即使非nil error從信道接收,仍繼續盡可能多的夠程就可以發送接收多次:

var errRec error
for _ = range addrs {
    if err := <-errc; err != nil {
        if errRec == nil {
            errRec = err
        }
    }
}
return errRec

或者如幻燈片#33上的鏈接談話中所述:使用“退出”通道來防止在broadcastMsg()完成/返回后啟動的goroutine保持阻塞狀態。

您有兩個地址列表(localhost,google)。 對於這些中的每一個,您使用每個地址使用一個goroutine發送消息(hi)。 並且goroutine向errc通道發送錯誤(可能是nil)。

如果你向某個頻道發送內容,你還需要一些東西來讀取該頻道的值,否則它會阻塞(除非它是一個緩沖的頻道,但是一旦它們的緩沖區已滿,即使是緩沖的頻道也會阻塞)。

所以你的閱讀循環看起來像這樣:

for _ = range addrs {
    if err := <-errc; err != nil {
        return err
    }
}

如果第一個地址返回的錯誤不是nil,則循環返回。 永遠不會從通道讀取后續錯誤值,因此它會阻塞。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM