几个月前,我在考虑如何在Go中为RPC库实现可关闭的事件循环。我设法像这样方便关闭服务器:
type Server struct {
listener net.Listener
closeChan chan bool
routines sync.WaitGroup
}
func (s *Server) Serve() {
s.routines.Add(1)
defer s.routines.Done()
defer s.listener.Close()
for {
select {
case <-s.closeChan:
// close server etc.
default:
s.listener.SetDeadline(time.Now().Add(2 * time.Second))
conn, _ := s.listener.Accept()
// handle conn routine
}
}
}
func (s *Server) Close() {
s.closeChan <- true // signal to close serve routine
s.routines.Wait()
}
我在这个实现中发现的问题是它涉及超时,这意味着最小关闭时间比它可能多2秒。是否有更惯用的方法来创建事件循环?
答案 0 :(得分:3)
我认为Go中的事件循环不需要循环。
在单独的goroutine中处理关闭和连接似乎更简单:
go func() {
<-s.closeChan
// close server, release resources, etc.
s.listener.Close()
}()
for {
conn, err := s.listener.Accept()
if err != nil {
// log, return
}
// handle conn routine
}
请注意,您也可以在不使用频道的情况下直接在关闭功能中关闭侦听器。我在这里所做的是使用Listener.Accept的错误返回值来促进例程间的通信。
如果在结束和连接处理实施的某个时刻,您需要保护您在回答时关闭的某些资源,则可以使用a Mutex。但通常可以避免这种情况。