我是golang
的新人,我遇到了这个问题。
我有几个channel
。
某些有效负载在不同时间到达此通道。
当通道准备吐出时,如何从通道中逐个获取所有值。
例如我写了这段代码:
package main
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")
}
但在这种情况下,我从其中一个频道获得第一个值。
请告诉我如何解决我的问题。
答案 0 :(得分:2)
你必须做几件事。
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")
}
执行时,我在屏幕上得到了以下输出。
6
1
7
2
3
4
8
5
9
10
Hello, test
答案 1 :(得分:1)
选择不等待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")
答案 2 :(得分:1)
您不必使用2个频道。只需使用1个通道并从多个goroutine中存储值。 Channel是轻量级的线程连接器,速度快,可以多次实例化以存储来自多个goroutine的值。
你的代码的问题是它没有循环来循环来自goroutines通道的值。您只能使用select打印一次。 select
让其他goroutines等到它执行一个可能的情况。如果所有情况都可能,那么它随机选择执行。
您只从频道获得一个值的原因是因为当您的goroutine工作时,它们会将数组中的值按顺序存储到频道。当发生这种情况时,您可以在主线程中使用case调用select
语句来获取goroutines中通道的值。由于您不会遍历频道,因此您只能从频道获取一个值,即首先收到的值。在这种情况下,您将数组按顺序循环到goroutine中的通道中,因此您将获得数组的第一个索引,因为它是首先发送到主线程中的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()
}
https://play.golang.org/p/32Fgetq_Zu7
希望它有所帮助。