【问题标题】:What is an idiomatic method of listening for events in Go?在 Go 中监听事件的惯用方法是什么?
【发布时间】:2012-11-10 13:10:05
【问题描述】:

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

【问题讨论】:

    标签: events concurrency go idioms event-loop


    【解决方案1】:

    我认为 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的错误返回值,方便程序间通信。

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

    【讨论】:

    • 监听器是线程安全的。从另一个 goroutine 关闭将立即强制 Accept() 返回错误。但是,您不能忽略该错误,否则您将陷入无限循环。
    • @StephenWeinberg 我很困惑 - 这如何退出服务功能?
    • @liamzebedee 当监听器关闭时,Accept 函数返回错误。这就是为什么如果你有这样的错误,我建议你返回。
    猜你喜欢
    • 2019-03-03
    • 1970-01-01
    • 2014-06-23
    • 1970-01-01
    • 2016-10-09
    • 2013-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多