为了账号安全,请及时绑定邮箱和手机立即绑定

等待 sync.Waitgroup in defer

等待 sync.Waitgroup in defer

Go
慕雪6442864 2022-01-17 20:01:42
从下面的 goroutine 在通道上发送时,我有以下代码进入死锁:package mainimport (    "fmt"    "sync")func main() {    for a := range getCh(10) {        fmt.Println("Got:", a)    }}func getCh(n int) <-chan int {    var wg sync.WaitGroup    ch := make(chan int)    defer func() {        fmt.Println("closing")        wg.Wait()        close(ch)    }()    wg.Add(1)    go func() {        defer wg.Done()        for i := 0; i < n; i++ {            ch <- i        }    }()    wg.Add(1)    go func() {        defer wg.Done()        for i := n; i < 0; i-- {            ch <- i        }    }()    return ch}我知道使用wg.Wait()in是合法的defer。但是我无法在以通道作为返回值的函数中找到用途。
查看完整描述

2 回答

?
Cats萌萌

TA贡献1805条经验 获得超9个赞

我认为您犯的错误是您认为该deferred函数也会异步运行。但事实并非如此,因此getCh()将在其延迟部分阻塞,等待 WaitGroup。但是由于没有人从通道读取,写入它的 goroutine 无法返回,因此 WaitGroup 导致死锁。尝试这样的事情:


func getCh(n int) <-chan int {

    ch := make(chan int)

    go func() {

        var wg sync.WaitGroup

        wg.Add(1)

        go func(n int) {

            defer wg.Done()

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

                ch <- i

            }

        }(n)

        wg.Add(1)

        go func(n int) {

            defer wg.Done()

            for i := n; i > 0; i-- {

                ch <- i

            }

        }(n)

        wg.Wait()

        fmt.Println("closing")

        close(ch)

    }()


    return ch

}


查看完整回答
反对 回复 2022-01-17
?
慕容708150

TA贡献1831条经验 获得超4个赞

看起来您的频道正在阻塞,因为您没有使用任何缓冲频道。看看这个简单的例子https://play.golang.org/p/zMnfA33qZk

ch := make(chan int, n)

请记住,通道在填充时会阻塞。我不确定您的代码目标是什么,但看起来您的目标是使用缓冲通道。这是来自 Effective go https://golang.org/doc/effective_go.html#channels的好作品

接收器总是阻塞,直到有数据要接收。如果通道没有缓冲,发送方会阻塞,直到接收方收到该值。如果通道有缓冲区,发送方只会阻塞,直到值被复制到缓冲区;如果缓冲区已满,这意味着要等到某个接收器检索到一个值。


查看完整回答
反对 回复 2022-01-17
  • 2 回答
  • 0 关注
  • 199 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号