扇入频道到单频道

时间:2018-07-09 05:54:46

标签: compose

我有几个通道c1,c2,c3,c4 ...,如何将所有数据从这些通道收集到一个通道中? 我的代码:

package main

import (
    "fmt"
    "sync"
)

func putToChannel(c chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 1; i < 6; i++ {
        c <- i
    }
}

func main() {
    c := make(chan int, 15)
    c1 := make(chan int, 5)
    c2 := make(chan int, 5)
    c3 := make(chan int, 5)
    go func(){c <- <-c1}()
    go func(){c <- <-c2}()
    go func(){c <- <-c3}()
    wg := new(sync.WaitGroup)
    wg.Add(3)
    go putToChannel(c1, wg)
    go putToChannel(c2, wg)
    go putToChannel(c3, wg)
    wg.Wait()
    close(c)
    for i := range c {
        fmt.Println("Receive:", i)
    }

    fmt.Println("Finish")
}

我想将c1,c2 ...到c的所有数据组合在一起,但是不起作用

3 个答案:

答案 0 :(得分:1)

本文很好地撰写了有关如何“渠道泛化”渠道的文章,包括停下来。 Link

这些行有问题:

go func(){c <- <-c1}()
go func(){c <- <-c2}()
go func(){c <- <-c3}()

其中的每一个将从cx频道接收一个值,并将该值发送到c

您需要一个看起来像这样的方法;

func merge(cs ...<-chan int) <-chan int {
    var wg sync.WaitGroup
    out := make(chan int)

    // Start an output goroutine for each input channel in cs.  output
    // copies values from c to out until c is closed, then calls wg.Done.
    output := func(c <-chan int) {
        for n := range c {
            out <- n
        }
        wg.Done()
    }
    wg.Add(len(cs))
    for _, c := range cs {
        go output(c)
    }

    // Start a goroutine to close out once all the output goroutines are
    // done.  This must start after the wg.Add call.
    go func() {
        wg.Wait()
        close(out)
    }()
    return out
}

此方法依赖于以下事实:当没有更多要发送的值时,将关闭传递到cs...的通道merge

这意味着您还需要更新putToChannel方法

func putToChannel(c chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    defer close(c)
    for i := 1; i < 6; i++ {
        c <- i
    }
}

值得注意的最后一件事是:尝试将创建并发送到通道的函数与关闭通道的函数封装为相同的函数。这意味着您将永远不会尝试在封闭的频道上进行发送。

代替:

c1 := make(chan int, 5)
go putToChannel(c1, wg)

可以的;

func generator() (<-chan int) {
    c := make(chan int, 5)
    go func() {
        for i := 1; i < 6; i++ {
             c <- i
        }
        close(c)
    }() 
    return c
}

您的主要方法如下所示:

func main() {
    var cs []<-chan int

    cs = append(cs, generator())
    cs = append(cs, generator())
    cs = append(cs, generator())

    c := merge(cs...)
    for v := range c {
        fmt.Println(v)
    }
}

答案 1 :(得分:0)

我对您的代码做了一些修改,如下所示。

基本上,在此示例中,需要执行三个步骤:

  1. 将值放入c1c2和,c3内,一旦完成输入值,别忘了关闭它们。
  2. 遍历需要与c合并到for-range中的每个通道,以将值放入c中。在for-range循环之后,您需要放入wg.Done(),以便可以发出信号,表明goroutine在完成每个通道的迭代后最终关闭c。如果有任何机会您没有关闭要合并到c的渠道之一,则会收到all goroutines are asleep - deadlock错误。
  3. 完成所有操作后,关闭c频道

这是修改后的代码:

package main

import (
    "fmt"
    "sync"
)

func putToChannel(c chan<- int) {
    for i := 1; i < 6; i++ {
        c <- i
    }
    //close the channel after putting values in
    close(c)
}

func main() {
    c := make(chan int, 15)
    c1 := make(chan int, 5)
    c2 := make(chan int, 5)
    c3 := make(chan int, 5)

    output := func(ch <-chan int, wg *sync.WaitGroup) {
        //you need to iterate over the channel
        for n := range ch {
            c <- n
        }
        wg.Done()
    }

    wg := new(sync.WaitGroup)
    wg.Add(3)
    go putToChannel(c1)
    go putToChannel(c2)
    go putToChannel(c3)
    go output(c1, wg)
    go output(c2, wg)
    go output(c3, wg)

    go func() {
        wg.Wait()
        close(c)
    }()
    for i := range c {
        fmt.Println("Receive:", i)
    }

    fmt.Println("Finish")
}

您可以找到更多信息here

答案 2 :(得分:0)

您可以这样做

package main

import (
    "fmt"
    "sync"
)

func putToChannel(c chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 1; i < 6; i++ {
        c <- i
    }
}

func main() {
    c := make(chan int, 15)
    c1 := make(chan int, 5)
    c2 := make(chan int, 5)
    c3 := make(chan int, 5)
    send := func(c1 chan int, c2 chan int) {
        for {
            value := <-c2
            c1 <- value
        }
    }
    go send(c, c1)
    go send(c, c2)
    go send(c, c3)
    wg := new(sync.WaitGroup)
    wg.Add(3)
    go putToChannel(c1, wg)
    go putToChannel(c2, wg)
    go putToChannel(c3, wg)
    wg.Wait()
    for i := 0; i < 15; i++ {
        fmt.Println("Receive:", <-c)
    }

    fmt.Println("Finish")
}

哪个输出:

Receive: 1
Receive: 2
Receive: 3
Receive: 4
Receive: 5
Receive: 1
Receive: 2
Receive: 3
Receive: 4
Receive: 5
Receive: 1
Receive: 2
Receive: 3
Receive: 4
Receive: 5
Finish