如何放置http.如果它阻塞了,就在自己的goroutine中服务



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产生错误,则会由于数据竞争而导致不一致的结果。

http.Serve要么在调用后立即返回错误,要么在成功执行时阻止

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

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

您可以在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出色的即时并发模式演讲可能会有所帮助。

最新更新