首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么戈鲁丁漏水

为什么戈鲁丁漏水
EN

Stack Overflow用户
提问于 2015-04-27 10:16:23
回答 2查看 4K关注 0票数 5

我在第30页上读到了12 Go最佳做法和遭遇以及有趣的例子。

代码语言:javascript
复制
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")
}

前面提到的程序员在上面提到的代码中出现了这种情况:

代码语言:javascript
复制
the goroutine is blocked on the chan write
the goroutine holds a reference to the chan
the chan will never be garbage collected

为什么戈鲁蒂河在这里被封锁了?主线程被阻塞,直到它从goroutine接收到数据。在它继续for循环之后。不?

为甚麽陈婉娴永远不会被收垃圾?因为我没有关闭通道,戈鲁丁完成了吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-04-27 10:27:03

我看到的一个问题是,在goroutines开始后,在broadcastMsg()内部:

代码语言:javascript
复制
for _ = range addrs {
    if err := <-errc; err != nil {
        return err
    }
}

如果从nil接收到非error,则broadcastMsg()将立即返回该错误,并且不会从通道接收进一步的值,这意味着更多的errc将永远不会被解除阻塞,因为errc是未缓冲的。

可能的修正

一个可能的解决方法是使用一个缓冲通道,在这种情况下,这个通道足够大到不阻塞任何一个goroutines:

代码语言:javascript
复制
errc := make(chan error, len(addrs))

或者,即使从频道接收到一个非nilerror,接收的数量仍然是它发送的数量的两倍:

代码语言:javascript
复制
var errRec error
for _ = range addrs {
    if err := <-errc; err != nil {
        if errRec == nil {
            errRec = err
        }
    }
}
return errRec

或者如在幻灯片#33上的链接对话中所提到的:使用“退出”通道来防止broadcastMsg()完成/返回后继续阻塞已启动的大猩猩。

票数 10
EN

Stack Overflow用户

发布于 2015-04-27 10:27:31

您有两个地址的列表(localhost,google)。对于每个地址,您都要发送一条消息(嗨),每个地址使用一个goroutine。而戈鲁蒂将错误(可能为零)发送到errc信道。

如果您向一个通道发送某种东西,您还需要从该通道读取值的东西,否则它将阻塞(除非它是一个缓冲通道,但即使是缓冲通道一旦缓冲区满了,也会阻塞)。

所以你的阅读循环是这样的:

代码语言:javascript
复制
for _ = range addrs {
    if err := <-errc; err != nil {
        return err
    }
}

如果第一个地址返回一个不为零的错误,则循环返回。以后的错误值永远不会从通道中读取,因此它会阻塞。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29892950

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档