Go程序没有死锁但也永远不会返回

gai*_*epr 0 go channels

附加的要点是一个使用生产者/多消费者模型中的渠道的简单程序.由于某些原因,

go run channels.go 打印所有结果但不返回(并且没有死锁或至少不会让我发生死锁的恐慌.)

type walkietalkie struct {
    in chan int
    out chan int
    quit chan bool
}

var items []int = []int{
    0, 1, 2, 3, 4, 5,
}

func work1(q walkietalkie) {
    for {
        select {
        case a, more := <- q.in:
            if more {
                q.out <- a * 2
            }
        default:
            break
        }
    }
}

func work2(q walkietalkie) {
    for  {
        select {
        case a, more := <- q.in:
            if more {
                q.out <- a * -1
            }
        default:
            break
        }
    }
}

func work3(q walkietalkie) {
    for  {
        select {
        case a, more := <- q.in:
            if more {
                q.out <- a * 7
            }
            default:
                break
        }
    }
}

func main() {
    results := make(chan int, 18)
    defer close(results)

    w := []walkietalkie{
        walkietalkie{ in: make(chan int, 6), out: results, quit: make(chan bool, 1) },
        walkietalkie{ in: make(chan int, 6), out: results, quit: make(chan bool, 1) },
        walkietalkie{ in: make(chan int, 6), out: results, quit: make(chan bool, 1) },
    }

    go work1(w[0])
    go work2(w[1])
    go work3(w[2])

    // Iterate over work items
    l := len(items)
    for i, e := range items {
        // Send the work item to each worker
        for _, f := range w {
            f.in <- e // send the work item
            if i == l - 1 { // This is the last input, close the channel
                close(f.in)
            }
        }
    }

    // Read all the results from the workers
    for {
        select {
        case r, more := <-results:
            if more {
                fmt.Println(r)
            } else {
                continue
            }
        default:
            break
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

sbe*_*rry 6

你有一些问题.

对于1,从具有多个返回值的通道读取,例如

case a, more := <-q.in 
Run Code Online (Sandbox Code Playgroud)

将继续关闭通道,将更多设置为false.在你的情况下,default永远不会被击中.

但这些都是在goroutines,并不会阻止程序退出.问题是你的主要goroutine正在做同样的事情.而且,事实证明,它break将会突破选择以及循环.因此,如果你想打破for循环,那么你需要使用一个标签并打破LABEL.

作为替代方案,您也可以返回而不是破坏主要的goroutine.