所有的Go程序都在睡觉(Go编程语言)



我正在学习Go编程语言和学习Go例程,遇到了以下问题。在本例中,下面的函数用于获取一个文件通道并处理每个文件:

func makeThumbnails5(filenames <-chan string) int64 {
sizes := make(chan int64)
var wg sync.WaitGroup
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
go func() {
wg.Wait()
close(sizes)
}()
var total int64
for size := range sizes {
total += size
}
wg.Wait()
return total
}

我试着用下面的方式使用这个函数:

func main() {
thumbnails := os.Args[1:] /* Get a list of all the images from the CLI */
ch := make(chan string, len(thumbnails))
for _, val := range thumbnails {
ch <- val
}
makeThumbnails5(ch)
}

然而,当我运行这个程序时,我得到以下错误:

fatal error: all goroutines are asleep - deadlock!

似乎没有更接近的例程正在运行。有人能帮助我了解这里出了什么问题,我能做些什么来正确运行这个功能?

正如我所评论的那样,它死锁是因为filenameschan从未关闭,因此for f := range filenames循环从未完成。然而,仅仅关闭输入chan意味着在循环中启动的所有例程都将卡在sizes <- info.Size()行,直到循环结束。在这种情况下不是问题,但如果输入可能很大,则可能会出现问题(那么您可能也想限制并发工作人员的数量)。因此,在程序中也有主循环是有意义的,以便for size := range sizes循环可以开始消费。

func makeThumbnails5(filenames <-chan string) int64 {
sizes := make(chan int64)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
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
go func() {
wg.Wait()
close(sizes)
}()
var total int64
for size := range sizes {
total += size
}
return total
}

main的实现有一个类似的问题,如果输入很大,你基本上是把它全部加载到内存中(缓冲chan),然后再把它传递给处理。也许像下面这样更好

func main() {
ch := make(chan string)
go func(thumbnails []string) {
defer close(ch)
for _, val := range thumbnails {
ch <- val
}
}(os.Args[1:])
makeThumbnails5(ch)
}

最新更新