douwang6635 2015-12-31 23:13
浏览 56
已采纳

“消费或放回” Go频道[重复]

This question already has an answer here:

I am trying to have two separate consumer go routines, that would filter out even and odd numbers from the input channel. This is just a toy example in order to see if it is possible to have consumers do something with the message read from the input channel if it matches certain condition, otherwise put back onto the input channel.

My current code is as follows:

package main

func filterOdd(ch chan int, out chan int) {
    val := <- ch
    if val % 2 == 0 {
        ch <- val
    } else {
        out <- val
    }
}
func filterEven(ch chan int, out chan int) {
    val := <- ch
    if val % 2 != 0 {
        ch <- val
    } else {
        out <- val
    }
}

func main() {
    even := make(chan int)
    odd := make(chan int)
    input := make(chan int)
    go filterOdd(input, odd)
    go filterEven(input, even)
    for i:=1; i <= 10; i++ {
        input <- i
    }

    println("Even...")
    for i := range even {
        println(i)
    }

    println("Odd...")
    for i := range odd {
        println(i)
    }
}

However, this produces the following output:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()
    /tmp/sandbox594577124/main.go:27 +0x140

goroutine 4 [chan send]:
main.filterOdd(0x10336100, 0x103360c0)
    /tmp/sandbox594577124/main.go:8 +0xc0
created by main.main
    /tmp/sandbox594577124/main.go:24 +0xc0

Link to the Go Playground: https://play.golang.org/p/9RIvFsGKI-

</div>
  • 写回答

1条回答 默认 最新

  • drjk87189 2016-01-01 01:49
    关注

    You have a deadlock because your even and odd goroutines are blocked on sending to out because nothing is reading from it. Why is nothing reading out? Because the main goroutine is blocked on sending to input because nothing is reading from it. Why is nothing reading from input? Because the two goroutines that would read from it are blocked.

    Also, both filterEven and filterOdd will only run once unless you wrap their contents in for { } (but then they'll never stop until you break). On the other hand, range even will block (and range odd never happens) when nothing is left to write to even , because range over a channel only stops when the channel is closed or break is called.

    In general, these aren't hard problems to solve as long as you know when you can close a channel. With what you're describing, that gets more difficult. None of the goroutines know when it's OK to close input, because all three write to it and two also read from it. You can use a sync.WaitGroup to make sure that everything you've put into the input channel has been processed before closing it. Once it's closed, the two other goroutines can use that as a signal to close their own channels and break or return to finish running.

    However, writes to the in and out channels will still block until there is a corresponding read, because they are unbuffered. However, if you buffer them by specifying a size as the second argument to make, writes won't block until the channel is full. Since you know neither even or odd will have more written to them than what main send to input, you can use that as a safe buffer capacity.

    Here's an example of using a WaitGroup with buffered channels for your code: https://play.golang.org/p/VXqfwUwRcx

    If you don't want buffered channels, you can also use another pair of goroutines to capture the values and send them back to main as slices once finished. This way writes on the even and odd channels don't block: https://play.golang.org/p/i5vLDcsK1v

    Otherwise, if don't need to print the contents of each channel all at once, you can use those two extra goroutines to read from the channels and print right away: https://play.golang.org/p/OCaUTcJkKB

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 stm32开发clion时遇到的编译问题