英文:
What is an idiomatic method of listening for events in Go?
问题
几个月前,我在思考如何在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:
// 关闭服务器等等
default:
s.listener.SetDeadline(time.Now().Add(2 * time.Second))
conn, _ := s.listener.Accept()
// 处理连接的例程
}
}
}
func (s *Server) Close() {
s.closeChan <- true // 信号关闭服务例程
s.routines.Wait()
}
我发现这种实现的问题是它涉及到一个超时,这意味着关闭时间至少比它应该多2秒。是否有更符合惯用方法的创建事件循环的方法?
英文:
A few months ago I was thinking how to implement a closable event loop in Go, for an RPC library. I managed to facilitate closing the server like so:
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()
}
The problem that I've found with this implementation is it involves a timeout, which means minimum close time is 2 seconds more than it could be. Is there a more idiomatic method of creating an event loop?
答案1
得分: 3
我不认为Go中的事件循环需要循环。
处理关闭和连接似乎更简单的方法是在单独的goroutine中处理:
go func() {
<-s.closeChan
// 关闭服务器,释放资源等等
s.listener.Close()
}()
for {
conn, err := s.listener.Accept()
if err != nil {
// 记录日志,返回
}
// 处理连接的例程
}
请注意,您也可以在Close函数中直接关闭监听器,而不使用通道。我在这里所做的是使用Listener.Accept的错误返回值来促进协程间的通信。
如果在关闭和连接处理实现的某个点上,您需要保护一些正在关闭时正在回答的资源,您可以使用互斥锁。但通常可以避免这种情况。
英文:
I don't think that event loops in Go need to be loops.
It would seem simpler to handle closing and connections in separate goroutines:
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
}
Note that you might also close the listener directly in your Close function without using a channel. What I have done here is used the error return value of Listener.Accept to facilitate inter-routine communication.
If at some point of the closing and connection handling implementations you need to protect some resources you're closing while you're answering, you may use a Mutex. But it's generally possible to avoid that.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论