当数据通道关闭时,Goroutines不会退出

时间:2014-08-26 21:37:12

标签: parallel-processing go goroutine

我试图按照http://blog.golang.org/pipelines/bounded.go发布的有限goroutine示例进行操作。我遇到的问题是,如果有更多的工作人员开始工作,那么额外的工作人员永远不会被取消。其他一切似乎都有效,价值得到计算和记录,但当我关闭groups频道时,工作人员只是挂在范围声明中。

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

更新

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
        }
    }
}

2 个答案:

答案 0 :(得分:2)

因为你试图从errc读取,除非出现错误,否则它是空的。

//修改

如果没有错误,

computeAll()将始终阻止<- errc,另一种方法是使用以下内容:

func computeAll() (err error) {
    .........
    select {
    case err = <-errc:
    default: //don't block
    }
    return
}

答案 1 :(得分:1)

尝试关闭errc,因为OneOfOne说

go func() {
    wg.Wait()
    close(c)
    close(errc)
}()

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

if err := range errc {
   if err != nil {
    return err
   }
}