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