Golang Goroutine错误“所有goroutine都在睡眠-死锁!" [英] Golang Goroutine Error "all goroutines are asleep - deadlock!"

查看:71
本文介绍了Golang Goroutine错误“所有goroutine都在睡眠-死锁!"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个代码来扫描从文件夹链接到我所有文件的文件,并根据他的内容和名字将正则表达式排在前十名"之列.文件.就其内容而言,我使用goroutine制作频道,但我不明白为什么每次我的goroutine都被锁定.这是我的代码:

 程序包主要进口 (旗帜""fmt""io/ioutil"正则表达式"运行"种类"同步"时间")var rName =".php"var rContent ="php"var maxSize,minSize int64var files_ten []文件func main(){开始:= time.Now()channelOne:= make(chan文件)channelTwo:= make(chan文件)var wg sync.WaitGroupvar路径字符串flag.StringVar(& path,"path",",文件夹的路径")flag.Parse()fmt.Println("Path =",path)对于我:= 0;我<runtime.NumCPU();我++ {进行检查(channelOne,channelTwo和&wg)}转到top10(channelTwo,& wg)wg.Wait()getFolder(path,channelOne,& wg)fmt.Println("top 10",files_ten)t:= time.Now()当前:= t.Sub(开始)fmt.Println(当前)}输入File struct {大小int64名称字符串路径字符串}func(此文件)GetSize()int64 {返回this.Size}func getFolder(路径字符串,channelOne chan文件,wg * sync.WaitGroup){文件夹err:= ioutil.ReadDir(path)如果err!= nil {fmt.Println("Error:",err)返回}对于_,数据:=范围文件夹{如果data.IsDir(){var newFolder字符串=路径+ data.Name()+"/"getFolder(newFolder,channelOne,wg)} 别的 {wg.Add(1)channelOne<-File {Size:data.Size(),Name:data.Name(),Path:path}}}}func check(channelOne chan File,channelTwo chan File,wg * sync.WaitGroup){为了 {文件:=< -channelOnerName:= regexp.MustCompile(rName)maxSize = 10000minSize = 0如果rName.MatchString(file.Name){如果file.Size< = maxSize&&file.Size> = minSize {f,err:= ioutil.ReadFile(file.Path +"/" + file.Name)如果err!= nil {fmt.Println("Error:",err)返回}rContent:= regexp.MustCompile(rContent)如果rContent.MatchString(string(f)){channelTwo<-文件} 别的 {wg.Done()}} 别的 {wg.Done()}} 别的 {wg.Done()}}}func sortFilesFromBiggestToLowerSize(arrayFile [] File)[] File {sort.Slice(arrayFile,func(i,j int)bool {返回arrayFile [i] .Size>arrayFile [j] .Size})返回arrayFile}func top10(channelTwo chan File,wg * sync.WaitGroup)[]文件{为了 {f:=< -channelTwo如果len(files_ten)== 10 {如果f.Size>files_ten [0] .Size ||f.大小>files_ten [len(files_ten)-1] .Size {files_ten = files_ten [:len(files_ten)-1]files_ten = append(files_ten,f)返回sortFilesFromBiggestToLowerSize(files_ten)}} 别的 {sortFilesFromBiggestToLowerSize(files_ten)返回append(files_ten,f)}wg.Done()返回files_ten}} 

这是我每次编译时的错误:

 开始运行filebysize.go --path = C:/wamp64/www/symfony/init/cours1/路径= C:/wamp64/www/symfony/init/cours1/致命错误:所有goroutine都在睡着-死锁!goroutine 1 [chan send]:main.getFolder(0xc04210a3c0,0x3d,0xc04204c0c0,0xc04204e210)C:/Users/Sahra/Documents/go/display/filebysize.go:72 + 0x28amain.getFolder(0xc04210a200、0x32、0xc04204c0c0、0xc04204e210)C:/Users/Sahra/Documents/go/display/filebysize.go:69 + 0x151main.getFolder(0xc04200e6c0,0x26,0xc04204c0c0,0xc04204e210)C:/Users/Sahra/Documents/go/display/filebysize.go:69 + 0x151main.getFolder(0xc042051f57,0x22,0xc04204c0c0,0xc04204e210)C:/Users/Sahra/Documents/go/display/filebysize.go:69 + 0x151main.main()C:/Users/Sahra/Documents/go/display/filebysize.go:37 + 0x2e0goroutine 19 [chan send]:main.check(0xc04204c0c0、0xc04204c120、0xc04204e210)C:/Users/Sahra/Documents/go/display/filebysize.go:95 + 0x2ec由main.main创建C:/Users/Sahra/Documents/go/display/filebysize.go:32 + 0x26dgoroutine 20 [chan send]:main.check(0xc04204c0c0、0xc04204c120、0xc04204e210)C:/Users/Sahra/Documents/go/display/filebysize.go:95 + 0x2ec由main.main创建C:/Users/Sahra/Documents/go/display/filebysize.go:32 + 0x26dgoroutine 21 [chan send]:main.check(0xc04204c0c0、0xc04204c120、0xc04204e210)C:/Users/Sahra/Documents/go/display/filebysize.go:95 + 0x2ec由main.main创建C:/Users/Sahra/Documents/go/display/filebysize.go:32 + 0x26dgoroutine 22 [chan send]:main.check(0xc04204c0c0、0xc04204c120、0xc04204e210)C:/Users/Sahra/Documents/go/display/filebysize.go:95 + 0x2ec由main.main创建C:/Users/Sahra/Documents/go/display/filebysize.go:32 + 0x26dgoroutine 23 [chan send]:main.check(0xc04204c0c0、0xc04204c120、0xc04204e210)C:/Users/Sahra/Documents/go/display/filebysize.go:95 + 0x2ec由main.main创建C:/Users/Sahra/Documents/go/display/filebysize.go:32 + 0x26dgoroutine 24 [chan send]:main.check(0xc04204c0c0、0xc04204c120、0xc04204e210)C:/Users/Sahra/Documents/go/display/filebysize.go:95 + 0x2ec由main.main创建C:/Users/Sahra/Documents/go/display/filebysize.go:32 + 0x26dgoroutine 25 [chan send]:main.check(0xc04204c0c0、0xc04204c120、0xc04204e210)C:/Users/Sahra/Documents/go/display/filebysize.go:95 + 0x2ec由main.main创建C:/Users/Sahra/Documents/go/display/filebysize.go:32 + 0x26dgoroutine 26 [chan send]:main.check(0xc04204c0c0、0xc04204c120、0xc04204e210)C:/Users/Sahra/Documents/go/display/filebysize.go:95 + 0x2ec由main.main创建C:/Users/Sahra/Documents/go/display/filebysize.go:32 + 0x26d退出状态2 

解决方案

您正尝试在 channelOne 上发送,但是直到wg.Done之后,任何内容都无法读取,因此陷入了僵局:例程尝试发送给它必须等到可以接收到某些东西为止,这永远不会发生.

此外,您的WaitGroup使用已关闭;您应该在启动每个要等待的goroutine之前调用 Add ,然后在goroutine的末尾调用 Done .单个goroutine不应在循环中调用 Add Done ,如果没有关联的 Add,则goroutine不应调用 Done 调用.

看来您有多个永不退出的 for 循环;他们没有条件,也没有 break .

您还可以更简单地遍历频道.您可以替换以下结构:

<{文件:=< -channelOne

更简单:

文件的

 := range channelOne { 

这样做还有一个好处,就是当您覆盖的频道关闭时,循环将退出,您可以使用关闭频道作为消费者可以停止的信号.

I am trying to make a code to scan from a folder link all my files and make a "top 10" by his size with also a regexp based on his content and his name. file. By it content, I make channels with goroutines but I dont understand why each time my goroutines are locked. Here is my code:

package main

import (
    "flag"
    "fmt"
    "io/ioutil"
    "regexp"
    "runtime"
    "sort"
    "sync"
    "time"
)

var rName = ".php"
var rContent = "php"
var maxSize, minSize int64
var files_ten []File

func main() {
    start := time.Now()

    channelOne := make(chan File)
    channelTwo := make(chan File)

    var wg sync.WaitGroup
    var path string
    flag.StringVar(&path, "path", "", "Path to folder")
    flag.Parse()
    fmt.Println("Path=", path)

    for i := 0; i < runtime.NumCPU(); i++ {
        go check(channelOne, channelTwo, &wg)
    }

    go top10(channelTwo, &wg)

    wg.Wait()

    getFolder(path, channelOne, &wg)

    fmt.Println("top 10", files_ten)
    t := time.Now()
    current := t.Sub(start)
    fmt.Println(current)

}

type File struct {
    Size int64
    Name string
    Path string
}

func (this File) GetSize() int64 {
    return this.Size
}

func getFolder(path string, channelOne chan File, wg *sync.WaitGroup) {
    folder, err := ioutil.ReadDir(path)

    if err != nil {
        fmt.Println("Error:", err)
        return
    }

    for _, data := range folder {
        if data.IsDir() {
            var newFolder string = path + data.Name() + "/"
            getFolder(newFolder, channelOne, wg)
        } else {
            wg.Add(1)
            channelOne <- File{Size: data.Size(), Name: data.Name(), Path: path}
        }
    }
}

func check(channelOne chan File, channelTwo chan File, wg *sync.WaitGroup) {
    for {
        file := <-channelOne
        rName := regexp.MustCompile(rName)

        maxSize = 10000
        minSize = 0

        if rName.MatchString(file.Name) {
            if file.Size <= maxSize && file.Size >= minSize {
                f, err := ioutil.ReadFile(file.Path + "/" + file.Name)

                if err != nil {
                    fmt.Println("Error:", err)
                    return
                }
                rContent := regexp.MustCompile(rContent)
                if rContent.MatchString(string(f)) {
                    channelTwo <- file
                } else {
                    wg.Done()
                }
            } else {
                wg.Done()
            }
        } else {
            wg.Done()
        }
    }
}

func sortFilesFromBiggestToLowerSize(arrayFile []File) []File {
    sort.Slice(arrayFile, func(i, j int) bool {
        return arrayFile[i].Size > arrayFile[j].Size
    })
    return arrayFile
}

func top10(channelTwo chan File, wg *sync.WaitGroup) []File {
    for {
        f := <-channelTwo

        if len(files_ten) == 10 {
            if f.Size > files_ten[0].Size || f.Size >
                files_ten[len(files_ten)-1].Size {
                files_ten = files_ten[:len(files_ten)-1]
                files_ten = append(files_ten, f)
                return sortFilesFromBiggestToLowerSize(files_ten)
            }
        } else {
            sortFilesFromBiggestToLowerSize(files_ten)
            return append(files_ten, f)
        }
        wg.Done()
        return files_ten
    }
}

Here is the error each time I compile it :

go run filebysize.go --path=C:/wamp64/www/symfony/init/cours1/
Path= C:/wamp64/www/symfony/init/cours1/
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.getFolder(0xc04210a3c0, 0x3d, 0xc04204c0c0, 0xc04204e210)
    C:/Users/Sahra/Documents/go/display/filebysize.go:72 +0x28a
main.getFolder(0xc04210a200, 0x32, 0xc04204c0c0, 0xc04204e210)
    C:/Users/Sahra/Documents/go/display/filebysize.go:69 +0x151
main.getFolder(0xc04200e6c0, 0x26, 0xc04204c0c0, 0xc04204e210)
    C:/Users/Sahra/Documents/go/display/filebysize.go:69 +0x151
main.getFolder(0xc042051f57, 0x22, 0xc04204c0c0, 0xc04204e210)
    C:/Users/Sahra/Documents/go/display/filebysize.go:69 +0x151
main.main()
    C:/Users/Sahra/Documents/go/display/filebysize.go:37 +0x2e0

goroutine 19 [chan send]:
main.check(0xc04204c0c0, 0xc04204c120, 0xc04204e210)
    C:/Users/Sahra/Documents/go/display/filebysize.go:95 +0x2ec
created by main.main
    C:/Users/Sahra/Documents/go/display/filebysize.go:32 +0x26d

goroutine 20 [chan send]:
main.check(0xc04204c0c0, 0xc04204c120, 0xc04204e210)
    C:/Users/Sahra/Documents/go/display/filebysize.go:95 +0x2ec
created by main.main
    C:/Users/Sahra/Documents/go/display/filebysize.go:32 +0x26d

goroutine 21 [chan send]:
main.check(0xc04204c0c0, 0xc04204c120, 0xc04204e210)
    C:/Users/Sahra/Documents/go/display/filebysize.go:95 +0x2ec
created by main.main
    C:/Users/Sahra/Documents/go/display/filebysize.go:32 +0x26d

goroutine 22 [chan send]:
main.check(0xc04204c0c0, 0xc04204c120, 0xc04204e210)
    C:/Users/Sahra/Documents/go/display/filebysize.go:95 +0x2ec
created by main.main
    C:/Users/Sahra/Documents/go/display/filebysize.go:32 +0x26d

goroutine 23 [chan send]:
main.check(0xc04204c0c0, 0xc04204c120, 0xc04204e210)
    C:/Users/Sahra/Documents/go/display/filebysize.go:95 +0x2ec
created by main.main
    C:/Users/Sahra/Documents/go/display/filebysize.go:32 +0x26d

goroutine 24 [chan send]:
main.check(0xc04204c0c0, 0xc04204c120, 0xc04204e210)
    C:/Users/Sahra/Documents/go/display/filebysize.go:95 +0x2ec
created by main.main
    C:/Users/Sahra/Documents/go/display/filebysize.go:32 +0x26d

goroutine 25 [chan send]:
main.check(0xc04204c0c0, 0xc04204c120, 0xc04204e210)
    C:/Users/Sahra/Documents/go/display/filebysize.go:95 +0x2ec
created by main.main
    C:/Users/Sahra/Documents/go/display/filebysize.go:32 +0x26d

goroutine 26 [chan send]:
main.check(0xc04204c0c0, 0xc04204c120, 0xc04204e210)
    C:/Users/Sahra/Documents/go/display/filebysize.go:95 +0x2ec
created by main.main
    C:/Users/Sahra/Documents/go/display/filebysize.go:32 +0x26d
exit status 2

解决方案

You're trying to send on channelOne, but nothing reads from it until after wg.Done, hence the deadlock: the routines trying to send to it must wait until something is available to receive, which never occurs.

Also, your WaitGroup use is off; you should call Add before starting each goroutine you want to wait on, then call Done at the end of the goroutine. A single goroutine should not call Add or Done in a loop, and a goroutine should not call Done if there is no associated Add call.

It looks like you have multiple for loops that will never exit; they have no conditions and no breaks.

You can also loop over channels much more simply. You can replace constructs like:

for {
    file := <-channelOne

with the simpler:

for file := range channelOne {

This has the added advantage that when the channel you're ranging over is closed, the loop will exit, allowing you to use closing the channel as a signal that consumers can stop.

这篇关于Golang Goroutine错误“所有goroutine都在睡眠-死锁!"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆