数据通道关闭时 Goroutines 不退出

我正在尝试遵循http://blog.golang.org/pipelines/bounded.go上发布的有界 goroutine 示例。我遇到的问题是,如果有更多的工作人员投入工作,那么工作量就会增加,额外的工作人员永远不会被取消。其他一切似乎都有效,值被计算并记录下来,但是当我关闭groups通道时,工作人员只是挂在 range 语句上。


我想我不明白(在我的代码和示例代码中)是工人如何知道何时没有更多工作要做以及他们应该退出?


更新


一个工作(即非工作)示例发布在http://play.golang.org/p/T7zBCYLECp。它显示了工人的僵局,因为他们都睡着了,没有工作要做。我感到困惑的是,我认为示例代码也会有同样的问题。


这是我目前使用的代码:


// Creates a pool of workers to do a bunch of computations

func computeAll() error {

    done := make(chan struct{})

    defer close(done)


    groups, errc := findGroups(done)


    // start a fixed number of goroutines to schedule with

    const numComputers = 20     

    c := make(chan result)

    var wg sync.WaitGroup

    wg.Add(numComputers)

    for i := 0; i < numComputers; i++ {

        go func() {

            compute(done, groups, c)

            wg.Done()

        }()

    }


    go func() {

        wg.Wait()

        close(c)

    }()


    // log the results of the computation

    for r := range c { // log the results }


    if err := <-errc; err != nil {

        return err

    }


    return nil

}

这是用数据填充通道的代码:


// Retrieves the groups of data the must be computed

func findGroups(done <-chan struct{}) (<-chan model, <-chan error) {

    groups := make(chan model)

    errc := make(chan error, 1)

    go func() {

        // close the groups channel after find returns

        defer close(groups)


        group, err := //... code to get the group ...

        if err == nil {

            // add the group to the channel

            select {

                case groups <- group:

            }

        }

    }()


    return groups, errc

}

这是读取通道以进行计算的代码。


// Computes the results for the groups of data

func compute(done <-chan struct{}, groups <-chan model, c chan<- result) {

    for group := range groups {

        value := compute(group)


        select {

        case c <- result{value}:

        case <-done:

            return

        }

    }

}


回首忆惘然
浏览 196回答 2
2回答

MM们

因为您正在尝试读取errc并且它是空的,除非出现错误。//编辑computeAll()<- errc如果没有错误,将始终阻止,另一种方法是使用类似的方法:func computeAll() (err error) {&nbsp; &nbsp; .........&nbsp; &nbsp; select {&nbsp; &nbsp; case err = <-errc:&nbsp; &nbsp; default: //don't block&nbsp; &nbsp; }&nbsp; &nbsp; return}

繁星coding

尝试像 OneOfOne 所说的那样关闭错误go func() {&nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; close(c)&nbsp; &nbsp; close(errc)}()// log the results of the computationfor r := range c { // log the results }if err := range errc {&nbsp; &nbsp;if err != nil {&nbsp; &nbsp; return err&nbsp; &nbsp;}}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go