使用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()
}

现在我正在尝试使用另一个程序从该通道读取。

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

如果我输入wgrad . add(2),它将打印上述DONE和false 3次。

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

break语句从最内部的for或switch语句中跳出来。当通道关闭时,在somechan上接收的函数在循环中旋转,减少等待组。像这样编写代码:

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

如果接收代码与问题中所写的一样,则可以消除接收例程。将wgread.Add(1)wgread.Wait()的代码替换为

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

break不打破外部for循环。要引用外部循环,可以使用这样的标签:

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

也是为了帮助编码风格,您应该练习使用gofmt来格式化代码。例如,它将用更简洁的for { ... }替换for ; ; { ... }

最新更新