簡體   English   中英

為什么在等待后關閉通道時所有 goroutine 都處於睡眠狀態?

[英]Why am I getting all goroutines are asleep when I close the channel after waiting?

以下是代碼:

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 的通道和並發新手,我將不勝感激!

編輯從操場鏈接添加了所有代碼

查看您的代碼,有兩件事可能導致死鎖:

  • errg.Wait()阻塞主 goroutine 的執行,直到所有初始化的 goroutine 完成。 但是,每個 goroutine 在嘗試寫入mapChan時都會被阻止,因為您永遠無法讀取它(因為它位於errg.Wait()下方)。
  • 你從來沒有讀過sliceChan ,所以這是一個潛在的死鎖。

是修改后的 Playground 代碼的鏈接,但大部分更改都在main的 function 中。

func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())
    m := makeData()
    errg := new(errgroup.Group)

    mapChan := make(chan StringAndData)
    sliceChan := make(chan *Result)
    mapDone := make(chan bool)
    sliceDone := make(chan bool)

    go func(){
        for ac := range mapChan {
            fmt.Println(ac.str)
        }
        mapDone <- true
    }()
    go func(){
        for ac := range sliceChan {
            fmt.Println(ac)
        }
        sliceDone <- true
    }()

    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)
    <-mapDone
    <-sliceDone
    fmt.Println("finished")

}

基本上,我改變了從mapChansliceChan通道讀取值的方式。 這是在單獨的 goroutine 中完成的,因此從這些通道中讀取不會被阻塞。

添加mapDonesliceDone通道只是為了確保在main goroutine 完成之前讀取所有數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM