Go 事件处理中的死锁
因此,我有一个用于事件处理的通道,主服务器goroutine在此通道上选择,并对接收到的每个事件调用事件处理程序:Go 事件处理中的死锁,go,goroutine,Go,Goroutine,因此,我有一个用于事件处理的通道,主服务器goroutine在此通道上选择,并对接收到的每个事件调用事件处理程序: evtCh := make(chan Event) // server loop: for !quit { select { case e := <- evtCh: handleEvent(e) break case quit := <-quitCh: //finish } // for send
evtCh := make(chan Event)
// server loop:
for !quit {
select {
case e := <- evtCh:
handleEvent(e)
break
case quit := <-quitCh:
//finish
}
// for send a new event to processing
func addEvent(e Event) {
evtCh <- e
}
evtCh:=make(chan事件)
//服务器循环:
对于退出{
挑选{
案例e:=
这将导致服务器挂起,因为事件处理程序本身是在服务器主循环的上下文中调用的
调用handleEvent时,主循环不应阻塞,避免阻塞的最常见方法是使用工作进程池。下面是一个未经测试的快速示例:
type Worker struct {
id int
ch chan Event
quit chan bool
}
func (w *Worker) start {
for {
select {
case e := <- w.ch:
fmt.Printf("Worker %d called\n", w.id)
//handle event
break;
case <- w.quit:
return
}
}
}
ch := make(chan Event, 100)
quit := make(chan bool, 0)
// Start workers
for i:=0; i<10; i++{
worker := &Worker{i,ch,quit}
go worker.start()
}
//
func addEvent (e Event) {
ch <- e
}
如果事先不知道事件的数量,您只需在退出通道上阻塞:
<- quit
要使事情更加异步,您可以
- 为事件频道添加容量
evtCh:=make(chan事件,10)
- 异步调用handleEvent(e)
go handleEvent(e)
- 在处理程序中异步添加事件
go addEvent(e)
或者,如果希望事件以确定性顺序处理,可以直接在处理程序中调用handleEvent(e)
,而不是addEvent(e)
谢谢,在这种情况下,主循环是什么样子的?您的意思是以循环方式向工作人员发送e?您不需要为循环做任何额外的事情。当您调用addEvent(myEvent)时
第一个空闲工作线程将捕获事件。我已经用一个主线程的示例扩展了答案。我想了解为什么将ch
设置为缓冲通道,与无缓冲通道相比有什么好处?@fluer缓冲通道将保护发送goroutine不被意外阻塞。如果偶尔,您所有的工作都会被阻塞er goroutines正忙,而您调用addEvent()
,该调用将被阻止。缓冲通道将允许您在所有工作人员都忙的情况下将事件推送到该通道。根据规范,当通道已满时,它也将被阻止,对吗?尽管我想实际上这种可能性很小。
<- quit