Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/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
Go 通道就绪时,从多个通道选择所有值_Go - Fatal编程技术网

Go 通道就绪时,从多个通道选择所有值

Go 通道就绪时,从多个通道选择所有值,go,Go,我是刚来戈朗的,我面临着这个问题 我有几个频道 一些有效载荷在不同的时间到达该通道 如何在通道准备吐出时,从通道中逐个获取所有值 例如,我编写了以下代码: 包干管 import ( "fmt" "time" "math/rand" ) func main() { arr1 := []int8{1,2,3,4,5} arr2 := []int8{6,7,8,9,10} c1 := make(chan int8) c2 := make(ch

我是刚来戈朗的,我面临着这个问题

我有几个频道

一些有效载荷在不同的时间到达该通道

如何在通道准备吐出时,从通道中逐个获取所有值

例如,我编写了以下代码:

包干管

import (
    "fmt"
    "time"
    "math/rand"
)

func main() {
    arr1 := []int8{1,2,3,4,5}
    arr2 := []int8{6,7,8,9,10}

    c1 := make(chan int8)
    c2 := make(chan int8)

    go func() {
        for _, val := range arr1 {
            time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
            c1 <- val
        }
    }()
    go func() {
        for _, val := range arr2 {
            time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
            c2 <- val
        }
    }()

    select {
        case res1 := <- c1:
            fmt.Println(res1)
        case res2 := <- c2:
            fmt.Println(res2)
    }

    fmt.Println("Hello, test")
}
但在这种情况下,我只从其中一个通道获得第一个值

请告诉我如何解决我的问题


链接到go play

选择不等待go例程。要实现这一点,您应该将其封装在for语句中。这样,select将一直运行,直到其中一个案例返回并中断for语句

for {
   select {
      ...
您还可以使用非阻塞和等待组的缓冲通道。像这样:

arr1 := []int8{1,2,3,4,5}
arr2 := []int8{6,7,8,9,10}

c1 := make(chan int8, len(arr1))
c2 := make(chan int8, len(arr2))

var wg sync.WaitGroup

wg.Add(1) // First wait group
go func() {
    for _, val := range arr1 {
        time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
        c1 <- val
    }
    wg.Done()
}()

wg.Add(1) // Second wait group
go func() {
    for _, val := range arr2 {
        time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
        c2 <- val
    }
    wg.Done()
}()

// executed after wg.Done() is called 2 times since we have 2 wait groups
wg.Wait() 

// We are not writing to channels anymore so we can close them.
close(c1)
close(c2)

for value := range c1 {
    fmt.Println(value)
}

for value := range c2 {
    fmt.Println(value)
}


fmt.Println("Hello, test")

你必须做几件事

1确保完成源代码后关闭频道。 2在通道上迭代,直到关闭

例如:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    arr1 := []int8{1, 2, 3, 4, 5}
    arr2 := []int8{6, 7, 8, 9, 10}

    c1 := make(chan int8)
    c2 := make(chan int8)

    go func() {
        for _, val := range arr1 {
            time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
            c1 <- val
        }
        close(c1)
    }()
    go func() {
        for _, val := range arr2 {
            time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
            c2 <- val
        }
        close(c2)
    }()

    _c1 := true
    _c2 := true
    var res1, res2 int8

    for _c1 == true || _c2 == true {
        select {
        case res1, _c1 = <-c1:
            if _c1 == true {
                fmt.Println(res1)
            }
        case res2, _c2 = <-c2:
            if _c2 == true {
                fmt.Println(res2)
            }
        }
    }

    fmt.Println("Hello, test")
}

你不必使用两个频道。只需使用1个通道并将多个goroutine中的值存储到其中。通道是轻量级线程连接器,速度快,可以多次实例化以存储来自多个goroutine的值

您的代码的问题是,它没有从goroutines通道返回的循环到循环的值。使用“选择”仅打印一次。select使其他goroutine等待,直到它执行它所拥有的一种可能的情况。如果所有的情况都是可能的,那么它会随机选择执行

您仅从通道获得一个值的原因是,当goroutine工作时,它们会按顺序将值从数组存储到通道。当这种情况发生时,您可以在主线程中调用select语句,并使用案例从goroutine中的通道获取值。由于您不在通道上循环,因此您只能从通道中获得一个值,即它第一次接收到的值。在本例中,您将按顺序将数组循环到goroutines中的通道中,因此您将获得数组的第一个索引,因为它是将首先发送到主线程中select语句的值。您选择的所有案例都可以执行,因此它将随机执行其中一个案例,您将在其中一个数组中获得第一个索引

要解决这个问题,您需要在通道上循环以逐个获取存储在其中的值。此外,您还需要同步所有线程以避免死锁情况,这种情况发生在主线程不知道何时停止从goroutine调用通道时,因为它们是异步工作的。您的通道在goroutines中获得值并被调用到循环中的主线程之后,就准备好吐出该值。代码如下:

package main

import (
    "fmt"
    "time"
    "math/rand"
    "sync"
)

// writer set numbers from array to channel
func writer(ch chan int, arr []int ,wgwrite *sync.WaitGroup) {
    defer wgwrite.Done()
    for _, val := range arr {
        time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
        ch <- val
    }
}

// reader receive input from writer channels and print them all 
func reader(ch chan int, wgread *sync.WaitGroup) {
  defer wgread.Done()
  for i:= range ch {
    fmt.Println(i)
  }
  fmt.Println("Hello, test")
}

func main() {
    arr1 := []int{1,2,3,4,5}
    arr2 := []int{6,7,8,9,10}
    ch := make(chan int)
    wgwrite := &sync.WaitGroup{}
    wgread  := &sync.WaitGroup{}

    wgwrite.Add(2)
    go writer(ch, arr1, wgwrite)
    go writer(ch, arr2, wgwrite)

    wgread.Add(1)
    go reader(ch, wgread)

    wgwrite.Wait()
    close(ch)
    wgread.Wait()
}

希望能有所帮助。

一种方法是将频道合并为一个频道,并在其上覆盖范围。参见示例中的风扇
package main

import (
    "fmt"
    "time"
    "math/rand"
    "sync"
)

// writer set numbers from array to channel
func writer(ch chan int, arr []int ,wgwrite *sync.WaitGroup) {
    defer wgwrite.Done()
    for _, val := range arr {
        time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
        ch <- val
    }
}

// reader receive input from writer channels and print them all 
func reader(ch chan int, wgread *sync.WaitGroup) {
  defer wgread.Done()
  for i:= range ch {
    fmt.Println(i)
  }
  fmt.Println("Hello, test")
}

func main() {
    arr1 := []int{1,2,3,4,5}
    arr2 := []int{6,7,8,9,10}
    ch := make(chan int)
    wgwrite := &sync.WaitGroup{}
    wgread  := &sync.WaitGroup{}

    wgwrite.Add(2)
    go writer(ch, arr1, wgwrite)
    go writer(ch, arr2, wgwrite)

    wgread.Add(1)
    go reader(ch, wgread)

    wgwrite.Wait()
    close(ch)
    wgread.Wait()
}