猿问

为什么我在等待后关闭频道时,所有 Goroutine 都处于睡眠状态?

代码如下:


func makeData() map[string][]Data {

    m := make(map[string][]Data)

    s := "abcdefghijklmno"


    for i, c := range s {

        data := []Data{

            {value: "hey_" + string(c), id: i * i},

            {value: "hello_" + string(c) + string(c), id: i + i},

            {value: "bye_" + string(c), id: i + 1},

        }

        m[strconv.Itoa(i)] = data

    }


    return m

}


func process(key string, value []Data) (*Result, error) {

    if key == "hey_a" {

        return nil, errors.New("error")

    }


    res := Result{data: Data{value: "hi", id: 0}, id: 1}

    return &res, nil

}


func main() {

    runtime.GOMAXPROCS(runtime.NumCPU())

    m := makeData()

    errg := new(errgroup.Group)


    mapChan := make(chan StringAndData)

    sliceChan := make(chan *Result)


    for key, value := range m {

        key := key

        value := value


        errg.Go(func() error {

            return func(key string, value []Data) error {

                res, err := process(key, value)

                if err != nil {

                    return err

                }

                if res == nil {

                    return nil

                }


                if res.data.id == 1 {

                    mapChan <- StringAndData{

                        str:  key,

                        data: res.data,

                    }

                    return nil

                }


                sliceChan <- res

                return nil


            }(key, value)

        })

    }


    if err := errg.Wait(); err != nil {

        fmt.Println("error")

    } else {

        fmt.Println("success")

    }


    close(mapChan)

    close(sliceChan)


    for ac := range mapChan {

        fmt.Println(ac.str)

    }

}


type Data struct {

    value string

    id    int

}


type Result struct {

    data Data

    id   int

}


type StringAndData struct {

    str  string

    data Data

}

操场


我得到了,但我正在关闭频道之后,我无法理解原因。fatal error: all goroutines are asleep - deadlock!errg.Wait()


我正在尝试打印使用 关闭通道后从通道获得的值。range


我是 Go 的渠道和并发新手,非常感谢任何帮助!


编辑添加了游乐场链接中的所有代码


明月笑刀无情
浏览 98回答 1
1回答

蝴蝶刀刀

查看代码,有两件事可能会导致死锁:errg.Wait()阻止主 goroutine 的执行,直到所有初始化的 goroutine 都完成。但是,在尝试写入 时,每个 goroutine 都会被阻止,因为您永远无法从中读取(因为它位于 )。mapChanerrg.Wait()你从来没有读过,所以这是一个潜在的死锁。sliceChan以下是修改后的 Playground 代码的链接,但大多数更改都在函数中。mainfunc main() {&nbsp; &nbsp; runtime.GOMAXPROCS(runtime.NumCPU())&nbsp; &nbsp; m := makeData()&nbsp; &nbsp; errg := new(errgroup.Group)&nbsp; &nbsp; mapChan := make(chan StringAndData)&nbsp; &nbsp; sliceChan := make(chan *Result)&nbsp; &nbsp; mapDone := make(chan bool)&nbsp; &nbsp; sliceDone := make(chan bool)&nbsp; &nbsp; go func(){&nbsp; &nbsp; &nbsp; &nbsp; for ac := range mapChan {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(ac.str)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; mapDone <- true&nbsp; &nbsp; }()&nbsp; &nbsp; go func(){&nbsp; &nbsp; &nbsp; &nbsp; for ac := range sliceChan {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(ac)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; sliceDone <- true&nbsp; &nbsp; }()&nbsp; &nbsp; for key, value := range m {&nbsp; &nbsp; &nbsp; &nbsp; key := key&nbsp; &nbsp; &nbsp; &nbsp; value := value&nbsp; &nbsp; &nbsp; &nbsp; errg.Go(func() error {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return func(key string, value []Data) error {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; res, err := process(key, value)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if res == nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if res.data.id == 1 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mapChan <- StringAndData{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; str:&nbsp; key,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data: res.data,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sliceChan <- res&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }(key, value)&nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; }&nbsp; &nbsp; if err := errg.Wait(); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("error")&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("success")&nbsp; &nbsp; }&nbsp; &nbsp; close(mapChan)&nbsp; &nbsp; close(sliceChan)&nbsp; &nbsp; <-mapDone&nbsp; &nbsp; <-sliceDone&nbsp; &nbsp; fmt.Println("finished")}基本上,我更改了从中读取值和通道的方式。这是在单独的goroutines中完成的,因此不会阻止从这些通道读取。mapChansliceChan添加 和 通道只是为了确保在 goroutine 完成之前读取所有数据。mapDonesliceDonemain
随时随地看视频慕课网APP

相关分类

Go
我要回答