如果阻止http.Serve如何在自己的goroutine中放置?

时间:2015-12-23 08:35:03

标签: go concurrency

http.Serve一旦调用就会返回错误,如果成功执行则会阻塞。

我怎样才能这样做,如果它阻止它在它自己的goroutine中这样做?我目前有以下代码:

func serveOrErr(l net.Listener, handler http.Handler) error {
    starting := make(chan struct{})
    serveErr := make(chan error)
    go func() {
        starting <- struct{}{}
        if err := http.Serve(l, handler); err != nil {
            serveErr <- err 
        }   
    }()
    <-starting

    select {
    case err := <-serveErr:
        return err
    default:
        return nil
    }
}

这似乎是一个良好的开端,适用于我的测试机器,但我相信不能保证在serveErr <- err之前调用case err := <-serveErr因此导致由于数据竞争而导致的结果不一致http.Serve {1}}会产生错误。

2 个答案:

答案 0 :(得分:4)

  

http.Serve在调用时会立即返回错误,如果成功执行则会阻塞

这个假设是不正确的。我相信它很少发生。 http.Serve在循环中调用net.Listener.Accept - 错误可能随时发生(套接字关闭,打开文件描述符太多等)。它的http.ListenAndServe通常用于运行http服务器,它通常在绑定侦听套接字时提前失败(没有权限,地址已在使用中)。

在我看来,你尝试做的事情是错误的,除非你的net.Listener.Accept因某种原因在第一次通话时失败了。是吗?如果你想100%确定你的服务器正在工作,你可以尝试连接它(也许实际上传输一些东西),但是一旦你成功绑定了套接字我就不会觉得它真的有必要。

答案 1 :(得分:1)

您可以在select语句中使用超时,例如

timeout := time.After(5 * time.Millisecond) // TODO: ajust the value
select {
case err := <-serveErr:
    return err
case _ := <- timeout:
    return nil
}

这样,您的选择将会阻止,直到serveErr有值或指定的timeout已过去。请注意,函数的执行将阻止调用goroutine,直到指定的超时持续时间。

Rob Pike关于go concurrency patterns的精彩演讲可能会有所帮助。