亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

為什么會出現致命錯誤:所有的 goroutines 都睡著了——死鎖!在這段代碼中?

為什么會出現致命錯誤:所有的 goroutines 都睡著了——死鎖!在這段代碼中?

Go
紅糖糍粑 2023-04-17 16:11:40
這是參考 The Go Programming Language - Chapter 8 p.238 中的以下代碼,從該鏈接下面復制// makeThumbnails6 makes thumbnails for each file received from the channel.// It returns the number of bytes occupied by the files it creates.func makeThumbnails6(filenames <-chan string) int64 {    sizes := make(chan int64)    var wg sync.WaitGroup // number of working goroutines    for f := range filenames {        wg.Add(1)        // worker        go func(f string) {            defer wg.Done()            thumb, err := thumbnail.ImageFile(f)            if err != nil {                log.Println(err)                return            }            info, _ := os.Stat(thumb) // OK to ignore error            fmt.Println(info.Size())            sizes <- info.Size()        }(f)    }    // closer    go func() {        wg.Wait()        close(sizes)    }()    var total int64    for size := range sizes {        total += size    }    return total}為什么我們需要將 closer 放在 goroutine 中?為什么下面不能工作?// closer        // go func() {        fmt.Println("waiting for reset")                wg.Wait()        fmt.Println("closing sizes")                close(sizes)        // }()如果我嘗試運行上面的代碼,它會給出:等待重置35472793致命錯誤:所有 goroutines 都睡著了 - 死鎖!為什么上面會出現死鎖?fyi,在調用的方法中makeThumbnail6我確實關閉了filenames頻道
查看完整描述

3 回答

?
手掌心

TA貢獻1942條經驗 獲得超3個贊

您的頻道是無緩沖的(您在 make()ing 頻道時沒有指定任何緩沖區大?。?。這意味著寫入通道會阻塞,直到寫入的值被讀取。在調用 wg.Wait() 之后,您從通道讀取數據,因此不會讀取任何內容,并且您的所有 goroutine 都會卡在阻塞寫入中。


也就是說,您在這里不需要 WaitGroup。當您不知道 goroutine 何時完成時,WaitGroups 很有用,但您正在發回結果,所以您知道。這是一個示例代碼,它執行與您嘗試執行的操作類似的操作(使用偽造的工作負載)。


package main


import (

? ? "fmt"

? ? "time"

)


func main() {

? ? var procs int = 0

? ? filenames := []string{"file1", "file2", "file3", "file4"}

? ? mychan := make(chan string)

? ? for _, f := range filenames {

? ? ? ? procs += 1

? ? ? ? // worker

? ? ? ? go func(f string) {

? ? ? ? ? ? fmt.Printf("Worker processing %v\n", f)

? ? ? ? ? ? time.Sleep(time.Second)

? ? ? ? ? ? mychan <- f

? ? ? ? }(f)

? ? }


? ? for i := 0; i < procs; i++ {

? ? ? ? select {

? ? ? ? case msg := <-mychan:

? ? ? ? ? ? fmt.Printf("got %v from worker channel\n", msg)

? ? ? ? }

? ? }

}


查看完整回答
反對 回復 2023-04-17
?
aluckdog

TA貢獻1847條經驗 獲得超7個贊

雖然提出問題已經有一段時間了,但我遇到了同樣的問題。最初我的主要內容如下所示:


func main() {

   filenames := make(chan string, len(os.Args))

   for _, f := range os.Args[1:] {

       filenames <- f

   }

   sizes := makeThumbnails6(filenames)

   close(filenames)

   log.Println("Total size: ", sizes)}

此版本死鎖,因為調用range filenames是makeThumbnails6同步的,因此close(filenames)in main 從未被調用。輸入的通道makeThumbnails6是無緩沖的,因此 goroutines 在嘗試發回大小時會阻塞。


close(filenames)解決方案是在 main 中進行函數調用之前移動。


查看完整回答
反對 回復 2023-04-17
?
嗶嗶one

TA貢獻1854條經驗 獲得超8個贊

代碼錯誤。簡而言之,通道sizes是無緩沖的。要修復它,我們需要在創建時使用具有足夠容量的緩沖通道sizes。一行修復就足夠了,如圖所示。這里我只是做了一個簡單的假設,1024足夠大。


func makeThumbnails6(filenames chan string) int64 {

    sizes := make(chan int64, 1024)    // CHANGE 

    var wg sync.WaitGroup // number of working goroutines

    for f := range filenames {

        wg.Add(1)

        // worker

        go func(f string) {

            defer wg.Done()

            thumb, err := thumbnail.ImageFile(f)

            if err != nil {

                log.Println(err)

                return

            }

            info, _ := os.Stat(thumb) // OK to ignore error

            fmt.Println(info.Size())

            sizes <- info.Size()

        }(f)

    }


    // closer

    go func() {

        wg.Wait()

        close(sizes)

    }()


    var total int64

    for size := range sizes {

        total += size

    }

    return total

}


查看完整回答
反對 回復 2023-04-17
  • 3 回答
  • 0 關注
  • 174 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號