dqdtgiw4736 2015-04-27 10:16
浏览 37
已采纳

为什么goroutine泄漏

I read Twelve Go Best Practices and encounter and interesting example on page 30.

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 programmer mentioned, that happens to the code above:

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

Why the goroutine is blocked here? The main thread is blocked, until it receive data from goroutine. After it continues the for loop. Not?

Why the errc chan will be never garbage collected? Because I do not close the channel, after goroutine is finished?

  • 写回答

2条回答 默认 最新

  • dongsu7049 2015-04-27 10:27
    关注

    One problem I see is that inside broadcastMsg() after goroutines have started:

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

    If a non-nil error is received from errc, broadcastMsg() returns immediately with that error and does not receive futher values from the channel, which means further goroutines will never get unblocked because errc is unbuffered.

    Possible Fixes

    A possible fix would be to use a buffered channel, big enough to not block any of the goroutines, in this case:

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

    Or even if a non-nil error is received from the channel, still proceed to receive as many times as many goroutines send on it:

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

    Or as mentioned in the linked talk on slide #33: use a "quit" channel to prevent the started goroutines to remain blocked after broadcastMsg() has completed/returned.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 Python语言实验
  • ¥15 SAP HANA SQL 增加合计行
  • ¥20 用C#语言解决一个英文打字练习器,有偿
  • ¥15 srs-sip外部服务 webrtc支持H265格式
  • ¥15 在使用abaqus软件中,继承到assembly里的surfaces怎么使用python批量调动
  • ¥15 大一C语言期末考试,求帮助🙏🙏
  • ¥15 ch340驱动未分配COM
  • ¥15 Converting circular structure to JSON
  • ¥30 Hyper-v虚拟机相关问题,求解答。
  • ¥15 TSM320F2808PZA芯片 Bootloader