2 回答
TA贡献1851条经验 获得超3个赞
您可以创建一个生产者/消费者系统:https : //play.golang.org/p/rks0gB3aDb
func main() {
ch := make(chan int)
clients := 4
// make it buffered, so all clients can fail without hanging
notifyCh := make(chan struct{}, clients)
go produce(100, ch, notifyCh)
var wg sync.WaitGroup
wg.Add(clients)
for i := 0; i < clients; i++ {
go func() {
consumer(ch, notifyCh)
wg.Done()
}()
}
wg.Wait()
}
func consumer(in chan int, notifyCh chan struct{}) {
fmt.Printf("Start consumer\n")
for i := range in {
<-time.After(100 * time.Millisecond)
if i == 42 {
fmt.Printf("%d fails\n", i)
notifyCh <- struct{}{}
return
} else {
fmt.Printf("%d\n", i)
}
}
fmt.Printf("Consumer stopped working\n")
}
func produce(N int, out chan int, notifyCh chan struct{}) {
for i := 0; i < N; i++ {
select {
case out <- i:
case <-notifyCh:
close(out)
return
}
}
close(out)
}
生产者将数字从 0 到 99 推送到通道,消费者一直消费直到通道关闭。在 main 中,我们创建了 4 个客户端并将它们添加到一个等待组中,以可靠地检查每个 goroutine 是否返回。每个消费者都可以在 notifyCh 上发信号,生产者停止工作并且不再产生更多的数字,因此所有消费者都在他们当前的数字之后返回。
还有一个选项可以创建4个go例程,等待它们全部返回,开始接下来的4个go例程。但这会增加等待的开销。
既然你提到了素数,这里有一个非常酷的素数:https ://golang.org/doc/play/sieve.go
TA贡献1936条经验 获得超6个赞
您是要为每个例程创建一个公共频道还是一个频道,取决于您想要什么。
如果你只想在里面放一些数字(或更一般的 - 请求)并且你不关心哪个 goroutine 提供服务,那么当然最好共享一个频道。例如,如果您希望 goroutine1 为前 250 个请求提供服务,那么您当然不能共享频道。
对于通道是一个很好的做法,将其用作输入或输出。发送者如何发送最简单的事情,他完成了关闭通道。关于这一点的好文章是https://blog.golang.org/pipelines
问题中没有提到的是 - 您是否还需要另一个通道(或多个通道)或任何其他通信原语来获得结果。这是比喂食更有趣的渠道。
应该发送什么信息 - 应该发送它,在每次 doTest 之后发送一个 bool,或者只知道什么时候完成了所有事情(在这种情况下,bool 都不需要只关闭一个通道)?
如果你喜欢程序一开始就失败。比我更喜欢使用缓冲共享通道来提供数字。不要忘记关闭它,当所有数字都将被馈送时。
另一个无缓冲的 chan 让主线程知道,测试已经完成。它可以是通道,在那里你只输入数字,测试失败的地方,或者如果你还想要一个肯定的结果 - 包含数字和结果的结构通道,或从 doTest 返回的任何其他信息。
关于频道的非常好的文章也是http://dave.cheney.net/2014/03/19/channel-axioms
您的四个 goroutine 中的每一个都可以报告失败(通过发送错误和关闭通道)。但是当所有数字都通过并且馈送通道关闭时,goroutines 应该做的是gotcha。关于那也是不错的文章http://nathanleclaire.com/blog/2014/02/15/how-to-wait-for-all-goroutines-to-finish-executing-before-continuing/
- 2 回答
- 0 关注
- 172 浏览
添加回答
举报