同时限制使用goroutins和渠道的消费者

时间:2013-12-21 01:07:36

标签: go

我试图重现“管理资源的方法是从请求通道开始读取固定数量的句柄goroutine。”来自Effective Go并找到了

fatal error: all goroutines are asleep - deadlock!

这个想法很简单:拥有1个队列和1个结果通道以及几个有限数量的“工人”。

我的代码是in Go Playground

queue := make(chan *Request)
result := make(chan int)
quit := make(chan bool)
go Serve(queue, quit)
for i := 0; i < 10; i++ {
    req := Request{i, result}
    queue <- &req
}
close(queue)
for i := 0; i < 10; i++ {
    fmt.Printf("Finished %d\n", <-result)
}
fmt.Printf("All finished\n")
quit <- true

功能服务:

func handle(queue chan *Request) {
    for r := range queue {
        //process(r)
        fmt.Printf("Processing %d\n", r.i)
        r.r <- r.i

    }
}

func Serve(clientRequests chan *Request, quit chan bool) {
    MaxOutstanding := 2
    // Start handlers
    for i := 0; i < MaxOutstanding; i++ {
        go handle(clientRequests)
    }
    <-quit // Wait to be told to exit.
}

有什么问题?或者可能有更简单的解决方案来实施处理请求的有限数量的工作人员?

1 个答案:

答案 0 :(得分:1)

结果通道未缓冲,因此每个发送都会阻止goroutine,直到某些内容收到结果。因此,在处理前两个项目之后,两个处理程序例程正在等待接收它们的结果。但接收工作项的代码尚未运行,因此它们被卡住了。然后main()尝试发送下一个工作项,处理程序还没有准备好接收它,所以main()现在也被卡住了。

解决此问题的一种方法是在排队工作项之前启动goroutine以在后台接收结果。以下是您在后台接收结果的代码版本,并使main()等待所有结果都被收到并处理完毕:http://play.golang.org/p/_CKn3CxQFc

在您的示例中,您可以通过计算收到的结果来了解何时退出是安全的。但是如果出现一种情况需要弄清楚你什么时候完成并且计数不够,那么1)每个工人都可以在完成时发出信号,2)Serve可以在所有工人发出信号后关闭结果通道已完成,3)您的结果处理goroutine可以在处理完所有结果后向quit发送main()。有很多变化;你可以在http://play.golang.org/p/12wZbm0rxa

看到代码