为什么会出现致命错误:所有goroutine都处于休眠状态-死锁!在这个代码中?
这是参考Go编程语言中的以下代码-第8章第238页,从下面的链接复制 如果我尝试运行上述代码,它会给出: 等待重置为什么会出现致命错误:所有goroutine都处于休眠状态-死锁!在这个代码中?,go,Go,这是参考Go编程语言中的以下代码-第8章第238页,从下面的链接复制 如果我尝试运行上述代码,它会给出: 等待重置 3547 2793 致命错误:所有goroutine都处于休眠状态-死锁 为什么在上面出现了僵局?仅供参考,在调用makeThumbnail6的方法中,我确实关闭了文件名通道您的通道是无缓冲的(在生成()通道时,您没有指定任何缓冲区大小)。这意味着对通道的写入会一直阻塞,直到写入的值被读取为止。在调用wg.Wait()之后,您从通道中读取数据,因此不会读取任何内容,并且所有的gor
3547
2793
致命错误:所有goroutine都处于休眠状态-死锁
为什么在上面出现了僵局?仅供参考,在调用
makeThumbnail6
的方法中,我确实关闭了文件名
通道您的通道是无缓冲的(在生成()通道时,您没有指定任何缓冲区大小)。这意味着对通道的写入会一直阻塞,直到写入的值被读取为止。在调用wg.Wait()之后,您从通道中读取数据,因此不会读取任何内容,并且所有的goroutine都会被阻塞写入
也就是说,这里不需要WaitGroup。当您不知道goroutine何时完成时,WaitGroups是很好的,但是您正在返回结果,所以您知道。下面是一个示例代码,它执行的操作与您尝试执行的操作(使用假工作负载)类似
主程序包
进口(
“fmt”
“时间”
)
func main(){
var procs int=0
文件名:=[]字符串{“file1”、“file2”、“file3”、“file4”}
mychan:=make(chan字符串)
对于uf:=范围文件名{
进程+=1
//工人
go func(f字符串){
fmt.Printf(“工人处理%v\n”,f)
时间。睡眠(时间。秒)
mychan虽然问题提出已经有一段时间了,但我遇到了同样的问题。最初我的主要观点如下:
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)}
func main(){
文件名:=make(chan字符串,len(os.Args))
对于uf:=范围os.Args[1:]{
文件名代码是错误的。简言之,通道大小
是无缓冲的。要修复它,我们需要在创建大小
时使用具有足够容量的缓冲通道。一个线性修复就足够了,如图所示。这里我只是简单地假设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
}
func makeThumbnails6(文件名和字符串)int64{
大小:=make(chan int641024)//更改
var wg sync.WaitGroup//工作goroutine的数量
对于f:=范围文件名{
工作组.添加(1)
//工人
go func(f字符串){
推迟工作组完成()
thumb,err:=缩略图.ImageFile(f)
如果错误!=零{
log.Println(错误)
回来
}
info,:=os.Stat(thumb)//确定忽略错误
fmt.Println(info.Size())
大小太好了!当我添加一个缓冲区时是的,比如size:=make(chan int64,10)
那么代码就可以工作了。谢谢你,疯了!呃……只有当你的有效负载数少于10时,它才会工作。这很脆弱。我强烈建议你像我发布的代码示例那样使用非阻塞读取。是的,我理解这一点,但它帮助我理解为什么会出现死锁。同意在实践中我会使用你共享的代码或他在书中写了一个:)谢谢。我不知道如何调用这个函数。
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)
}
}
}
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)}
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
}