总是与渠道陷入僵局

时间:2018-11-26 13:23:11

标签: go channels

我正在学习使用Go频道,并且总是陷入僵局。此代码可能有什么问题?当阵列大小不相等时,打印机会随机停止工作;我想这将有助于以某种方式通知打印机接收器停止工作。任何想法如何解决?我的代码粘贴在下面。

package main

import (
    "fmt"
    "sync"
)

var wg = sync.WaitGroup{}
var wgs = sync.WaitGroup{}
var sg = make(chan int, 50)
var gp1 = make(chan int, 50)
var gp2 = make(chan int, 50)

func main(){
    wgs.Add(2)
    go Sender(0)
    go Sender(11)

    wg.Add(3)
    go Receiver()

    go Printer()
    go Printer2()

    wg.Wait()
}

func Sender(start int){
    defer wgs.Done()
    for i := start; i < 20; i++ {
        sg <- i
    }
}

func Receiver(){
    defer wg.Done()
    for i := 0; i < 20; i++{
        nr := <- sg
        if nr % 2 == 0{
            gp1 <- nr
        } else{
            gp2 <- nr
        }
    }
}

func Printer(){
    defer wg.Done()
    var m [10]int

    for i := 0; i < 10; i++ {
        m[i] = <- gp1
    }

    wgs.Wait()
    fmt.Println(m)
}

func Printer2(){
    defer wg.Done()
    var m [10]int

    for i := 0; i < 10; i++ {
        m[i] = <- gp2
    }

    wgs.Wait()

    fmt.Println(m)
}
// Better to use this one
// func Receiver(senderChannel <-chan int, printerChannel1 chan<- int, printerChannel2 chan<- int, wg *sync.WaitGroup) {

2 个答案:

答案 0 :(得分:0)

发件人生成(我认为有28条消息)。前20个中的大约一半分配给gp1和gp2中的一个。然后Printer和Printer2卸载消息

问题是,接收方拆分邮件的方式取决于接收到的数字是奇数还是偶数。但是您并没有为此而控制。如果其中一台打印机的队列中的物品少于10件,它将挂起

那是一个潜在的问题

答案 1 :(得分:0)

您的核心问题是,其中的所有内容都是“错误的推算”:他们希望看到固定数量的消息,但这不一定与现实相符。您应该设置通道,以便一旦产生所有数据就将其关闭。

这可能意味着设置一个中间功能来管理发送:

func Sender(from, to int, c chan<- int) {
    for i := from; i < to; i++ {
        c <- i
    }
}

func SendEverything(c chan<- int) {
    var wg sync.WaitGroup
    wg.Add(2)
    go func() {
        defer wg.Done()
        Sender(0, 20, c)
    }()
    go func() {
        defer wg.Done()
        Sender(11, 20, c)
    }()
    wg.Wait()
    close(c)
}

使调度程序功能可在通道中的所有功能上工作:

func Receive(c <-chan int, odds, evens chan<- int) {
    for n := range c {
        if n%2 == 0 {
            evens <- n
        } else {
            odds <- n
        }
    }
    close(odds)
    close(evens)
}

然后您可以共享一个打印功能:

func Printer(prefix string, c <-chan int) {
    for n := range c {
        fmt.Printf("%s: %d\n", prefix, n)
    }
}

最后,您有一个将所有功能缝合在一起的主要功能:

func main() {
    var wg sync.WaitGroup
    inputs := make(chan int)
    odds := make(chan int)
    evens := make(chan int)

    wg.Add(4)
    go func() {
        defer wg.Done()
        SendEverything(inputs)
    }()
    go func() {
        defer wg.Done()
        Receive(inputs, odds, evens)
    }()
    go func() {
        defer wg.Done()
        Printer("odd number", odds)
    }()
    go func() {
        defer wg.Done()
        Printer("even number", evens)
    }()
    wg.Wait()
}

完整的示例在https://play.golang.org/p/qTUqlt-uaWH

请注意,我完全避免使用任何全局变量,并且任何东西都希望有一个不言自明的非常短的名称(in是简单的整数,c是频道)或完整的单词(oddsevens)。我倾向于将sync.WaitGroup对象保留在其创建位置的本地。由于所有内容都是作为参数传递的,因此我不需要同一个函数的两个副本来作用于不同的全局变量,并且如果我选择为此编写测试代码,则可以创建自己的本地通道。