Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 如何等待一组goroutine中的任何一个发出信号,而不要求我们等待他们这样做_Multithreading_Go_Producer Consumer_Goroutine - Fatal编程技术网

Multithreading 如何等待一组goroutine中的任何一个发出信号,而不要求我们等待他们这样做

Multithreading 如何等待一组goroutine中的任何一个发出信号,而不要求我们等待他们这样做,multithreading,go,producer-consumer,goroutine,Multithreading,Go,Producer Consumer,Goroutine,有很多例子说明如何使用WaitGroup来等待一组goroutine的全部完成,但是如果您想等待其中任何一个完成,而不使用信号量系统(其中某些进程必须等待),该怎么办?例如,生产者/消费者场景,其中多个生产者线程向数据结构添加多个条目,而消费者一次删除一个条目。在这种情况下: 我们不能只使用标准的生产者/消费者信号系统,因为生产:消费不是1:1,而且数据结构充当缓存,因此生产者可以“自由运行”而不是阻塞,直到消费者“准备好”消费他们的产品 消费者可能会清空数据结构,在这种情况下,消费者希望等待

有很多例子说明如何使用WaitGroup来等待一组goroutine的全部完成,但是如果您想等待其中任何一个完成,而不使用信号量系统(其中某些进程必须等待),该怎么办?例如,生产者/消费者场景,其中多个生产者线程向数据结构添加多个条目,而消费者一次删除一个条目。在这种情况下:

  • 我们不能只使用标准的生产者/消费者信号系统,因为生产:消费不是1:1,而且数据结构充当缓存,因此生产者可以“自由运行”而不是阻塞,直到消费者“准备好”消费他们的产品
  • 消费者可能会清空数据结构,在这种情况下,消费者希望等待任何一个生产者完成(这意味着数据结构中可能有新的内容)
问题:有标准的方法吗?

我只能想出两种方法来做这件事。通过使用通道作为信号量:

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
}
var单通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道通道
func my_goroutine(){
//生产,生产,生产!!!

单声道您可以使用具有如下缓冲区的声道

// 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)
    }
}
//创建一个缓冲区为1的通道
var项目=制造(成交量,1)
var MyArray[]int
func main(){
转到附加项()
转到附加项()
转到附加项()
转到sendToChannel()
真的{
fmt.Println(0{

项目你能澄清一下你的样本中有什么
要消费的东西吗?
是我的goroutine附加的一个片段吗?没关系。它可以是一个数据库、一个堆栈、一个队列。关键是,它要么为消费者准备了一些东西(以便消费者可以从中弹出一个值),要么是空的(消费者希望停止消耗CPU周期,直到生产者发出信号表示已向其添加内容)。这很重要。通道的行为与您描述的完全相同。因此,生产者将其结果发送到通道中,消费者可以通过多种方式实现;阻塞、非阻塞、超时等。如果未缓冲,写入通道将阻塞生产者。如果缓冲,则必须使缓冲区与您预期的后日志一样大这有几个问题。首先,一旦len(Items)降为零,main()基本上将进入自旋锁,在疯狂地重新检查项目长度的同时驱动CPU负载(这就是在制作人发出新的信号之前阻止消费者的全部目的。事实上,你最好删除len(Items)检查,让channel read操作阻止消费者)。其次,它要求您制作一个频道,其大小与您所期望看到的最大积压一样大,这是浪费(和/或有可能阻止制作者)。您可以将项目附加到数组中,将其推送到频道,然后弹出数组,如我的编辑中所示
// 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)
    }
}