等待 sync.Waitgroup in defer

从下面的 goroutine 在通道上发送时,我有以下代码进入死锁:


package main


import (

    "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。但是我无法在以通道作为返回值的函数中找到用途。


慕雪6442864
浏览 200回答 2
2回答

Cats萌萌

我认为您犯的错误是您认为该deferred函数也会异步运行。但事实并非如此,因此getCh()将在其延迟部分阻塞,等待 WaitGroup。但是由于没有人从通道读取,写入它的 goroutine 无法返回,因此 WaitGroup 导致死锁。尝试这样的事情:func getCh(n int) <-chan int {&nbsp; &nbsp; ch := make(chan int)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; var wg sync.WaitGroup&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; go func(n int) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for i := 0; i < n; i++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ch <- i&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }(n)&nbsp; &nbsp; &nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; &nbsp; &nbsp; go func(n int) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; defer wg.Done()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for i := n; i > 0; i-- {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ch <- i&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }(n)&nbsp; &nbsp; &nbsp; &nbsp; wg.Wait()&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("closing")&nbsp; &nbsp; &nbsp; &nbsp; close(ch)&nbsp; &nbsp; }()&nbsp; &nbsp; return ch}

慕容708150

看起来您的频道正在阻塞,因为您没有使用任何缓冲频道。看看这个简单的例子https://play.golang.org/p/zMnfA33qZkch := make(chan int, n)请记住,通道在填充时会阻塞。我不确定您的代码目标是什么,但看起来您的目标是使用缓冲通道。这是来自 Effective go https://golang.org/doc/effective_go.html#channels的好作品接收器总是阻塞,直到有数据要接收。如果通道没有缓冲,发送方会阻塞,直到接收方收到该值。如果通道有缓冲区,发送方只会阻塞,直到值被复制到缓冲区;如果缓冲区已满,这意味着要等到某个接收器检索到一个值。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go