有很多关于如何使用WaitGroup等待一组goroutine的所有来完成的例子,但是如果你想等待任何一个的话他们完成而不使用信号量系统,其中一些进程必须等待?例如,生产者/消费者场景,其中多个生产者线程将多个条目添加到数据结构,而消费者一次一个地删除它们。在这种情况下:
问题:有没有标准方法可以做到这一点?
我只能设计两种方法。两者都使用通道作为信号量:
var unitary_channel chan int = make(chan int, 1)
func my_goroutine() {
// Produce, produce, produce!!!
unitary_channel<-0 // Try to push a value to the channel
<-unitary_channel // Remove it, in case nobody was waiting
}
func main() {
go my_goroutine()
go my_goroutine()
go my_goroutine()
for len(stuff_to_consume) { /* Consume, consume, consume */ }
// Ran out of stuff to consume
<-unitary_channel
unitary_channel<-0 // To unblock the goroutine which was exiting
// Consume more
}
现在,这个简单的例子有一些明显的(但是可以解决的问题),比如如果至少有一个go_routine()仍在运行,main()就不会退出。
第二种方法,不是要求生产者删除它们刚刚推送到通道的值,而是使用 select 来允许生产者在通道阻止它们时退出。
var empty_channel chan int = make(chan int)
func my_goroutine() {
// Produce, produce, produce!!!
select {
case empty_channel <- 0: // Push if you can
default: // Or don't if you can't
}
}
func main() {
go my_goroutine()
go my_goroutine()
go my_goroutine()
for len(stuff_to_consume) { /* Consume, consume, consume */ }
// Ran out of stuff to consume
<-unitary_channel
// Consume more
}
当然,如果所有goroutine都已经终止,那么这个也永远阻止main()。 所以,如果第一个问题的答案是&#34;否,除了你提出的问题之外没有其他标准的解决方案,是否有令人信服的理由?为什么应该使用其中一个而不是另一个?
答案 0 :(得分:0)
您可以使用带有缓冲区的频道
// create a channel with a buffer of 1
var Items = make(chan int, 1)
var MyArray []int
func main() {
go addItems()
go addItems()
go addItems()
go sendToChannel()
for true {
fmt.Println(<- Items)
}
}
// push a number to the array
func addItems() {
for x := 0; x < 10; x++ {
MyArray = append(MyArray, x)
}
}
// push to Items and pop the array
func sendToChannel() {
for true {
for len(MyArray) > 0 {
Items <- MyArray[0]
MyArray = MyArray[1:]
}
time.Sleep(10 * time.Second)
}
}
main中的for循环将循环播放并打印任何添加到通道的内容,sendToChannel函数将在数组为空时阻塞,
通过这种方式,生产者永远不会被阻止,消费者可以在有一个或多个可用项目时消费