【问题标题】:Reading from a concurrent function via channel using goroutine and a closure giving error使用 goroutine 和闭包通过通道从并发函数中读取错误
【发布时间】:2016-12-22 21:58:51
【问题描述】:

我有一个正在写入通道的函数(不是闭包)。我正在从 goroutine 调用该函数

var wg sync.WaitGroup
wg.Add(1)
go DoStuff(somechan, &wg)

在 DoStuff 里面,我有类似的东西

for ; ; {

    if err == io.EOF { 
        fmt.Println(err)
        close(somechan)
        fmt.Println("Closed channel")
        break
    } else if err != nil {
        panic(err)
    }
    somechan <- Somefunc()
}

现在我正在尝试使用另一个 goroutine 从该频道读取数据。

wgread.Add(1)
go func() {
    for ; ; {
        select {
        case chanoutput, ok := <-somechan:
            if ok == true {
                fmt.Println(string(*chanoutput))
            } else {
                fmt.Println("DONE")
                fmt.Println(ok)
                wgread.Done()
                break
            }
        }

    }
}()
wgread.Wait()

但是,当我跑步时,我得到了

panic: sync: negative WaitGroup counter

打印后

DONE
false
DONE
false

如果我给 wgread.Add(2),它将打印上面的 DONE 和 false 3 次。

虽然我将等待组增量增加了 1,但为什么会给出一个负的等待组计数器错误?使用另一个并发函数或闭包从 goroutine 中读取的最佳方法是什么?

【问题讨论】:

  • 这里的代码不足以说明问题。

标签: go synchronization closures channel goroutine


【解决方案1】:

break 语句打破了最里面的 case,for 或 switch 语句。在somechan 上接收的函数在一个循环中旋转,当通道关闭时减少等待组。编写如下代码:

wgread.Add(1)
go func() {
    defer wgread.Done()
    for chanoutput := range somechan {
        fmt.Println(string(*chanoutput))
    }
    fmt.Println("DONE")
}()
wgread.Wait()

如果接收代码和问题中写的一样,那么接收goroutine可以消除。将代码从wgread.Add(1) 替换为wgread.Wait()

for chanoutput := range somechan {
    fmt.Println(string(*chanoutput))
}

【讨论】:

    【解决方案2】:

    break 不会破坏外部 for 循环。 要引用外部循环,您可以使用如下标签:

    Loop:
        for {
            select {
                case ...:
                    break Loop
            }
        }
    

    也有助于编码风格, 你应该练习使用gofmt 来格式化你的代码。例如,它将for ; ; { ... } 替换为更清洁的for { ... }

    【讨论】:

    • 谢谢@Baloo,但是有了break Loop,主线程现在正在等待。
    猜你喜欢
    • 1970-01-01
    • 2022-01-02
    • 2019-11-18
    • 1970-01-01
    • 2018-09-29
    • 2016-05-31
    • 1970-01-01
    • 2020-06-26
    • 2023-03-16
    相关资源
    最近更新 更多