2017-12-14 21 views
1

私はすべてのファイルをフォルダリンクからスキャンし、彼のサイズと彼の名前に基づいて正規表現で自分のサイズで "トップ10"を作るようにしようとしています。ファイル。コンテンツでは、私はgoroutinesでチャンネルを作っていますが、私のgoroutinesがロックされるたびに理由を理解できません。ここでGolang Goroutineエラー "すべてのゴルーチンが眠っています - デッドロックです!"

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 
    } 
} 

エラーは、私はそれをコンパイルするたびにされています:ここに私のコードです

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 
+0

これは理解しなければならないコードですが、いくつかのことが分かります: 'top10'からの戻り値は無視され、waitgroupはgoroutinesを実行する以外の何かを数えるために使われます。 –

+0

あなたは正しいです、問題は、関数トップ10で、私は何かを返す必要はありません、if elseステートメントで、たくさんありがとう!!!!!!!!!!!!!!!!!!を含める必要はありませんでした!! –

答えて

1

あなたはchannelOneに送信しようとしているが、何もそれゆえ、wg.Done後までそれから読みませんデッドロック:それを送信しようとするルーチンは、何かが受信可能になるまで待たなければなりません。

また、WaitGroupの使用はオフです。待つべき各ゴルーチンを起動する前にAddに電話をかけてから、ゴルーチンの最後にDoneを呼び出してください。単一のゴルーチンは、AddまたはDoneをループで呼び出すべきではなく、Add呼び出しがない場合、ゴルーチンはDoneを呼び出すべきではありません。

終了することのない複数のforループがあるようです。条件はなく、breakはありません。

さらに簡単にチャンネルをループすることもできます。単純に

for { 
    file := <-channelOne 

:あなたのような構造を置き換えることができます

for file := range channelOne { 

これは、あなたが使用できるように、あなたはオーバーまでしているチャネルが閉じているとき、ループが終了するという追加の利点を持っています消費者が止めることができる信号としてチャネルを閉じる。

関連する問題