2

几个月前,我在考虑如何在 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 秒。有没有更惯用的方法来创建事件循环?

4

1 回答 1

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
}

请注意,您也可以在不使用通道的情况下直接在 Close 函数中关闭侦听器。我这里做的是使用Listener.Accept的错误返回值来方便程序间通信。

如果在关闭和连接处理实现的某个时刻,您需要保护正在关闭的某些资源,而您正在回答,您可以使用Mutex。但通常可以避免这种情况。

于 2012-11-22T07:34:50.517 回答