undefinedfix
Sign in

A problem about the leakage of goroutines in go language

ixepc edited in Sat, 30 Jul 2022

Problem description

In reading the Bible of go language, I don't understand the description of using waitgup to deal with goroutines leakage in the chapter of "concurrent loops". Please give me your advice.

The book describes:

If the wait operation is placed in the main goroutine, before the loop, it will never end

I don't understand why it's necessary to put it here wg.Wait () in a goroutine? Why put it in main goroutine and it will never end?

Related codes

// Please paste the code text below (do not use pictures instead of codes)

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
            sizes <- info.Size()
        }(f)
    }

    // closer
    go func() { // 为什么一定要在goroutine中进行执行?
        wg.Wait()
        close(sizes)
    }()

    var total int64
    for size := range sizes {
        total += size
    }
    return total
}
2 Replies
xtu
commented on Sun, 31 Jul 2022

Putting it in the main goroutine causes a deadlock, whether before or after the Chan read

It's essentially because I don't know how many worker goroutines there will be


Before the channel is read, the worker's write channel will block

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) 
            sizes <- info.Size()  // 阻塞在这里,因为没有办法读取
        }(f)
    }

    // closer
    wg.Wait()      // 阻塞在这里
    close(sizes)

    var total int64
    for size := range sizes {
        total += size
    }
    return total
}

After reading the channel, it will always block the place where the channel is read

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) 
            sizes <- info.Size()  
        }(f)
    }



    var total int64
    for size := range sizes {   // 阻塞在这里
        total += size
    }
    
    // closer
    wg.Wait()     
    close(sizes)
    
    return total
}
Yoshi
commented on Sun, 31 Jul 2022

Notes before: sizes in worker<- info.Size () is blocked, unable to go to defer wg.Done () , wg.Wait () is also blocked, so we can't get there

for size := range sizes {  
      total += size      
}

Sizes cannot be read, resulting in deadlock

After: because there is no close (sizes)

for size := range sizes {  
      total += size      
}

Blocking all the time, causing a deadlock

https :// stackoverflow . com / que ...

lock This question has been locked and the reply function has been disabled.