2017-12-14 33 views
1

나는 모든 파일을 폴더 링크에서 스캔하고 자신의 콘텐츠와 이름을 기반으로하는 정규식을 사용하여 자신의 크기로 "톱 10"을 만드는 코드를 만들려고합니다. 파일. 내용으로 볼 때, 나는 goroutine으로 채널을 만들었지 만, 내 goroutine이 잠길 때마다 이유를 이해하지 못합니다. 여기Golang Goroutine 오류 "모든 goroutines이 잠 들어 있습니다 - 교착 상태입니다!"

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 사용이 꺼져 있습니다. 기다리고 싶은 각 goroutine을 시작하기 전에 Add으로 전화 한 다음 goroutine 끝에 Done을 호출해야합니다. 단일 goroutine은 루프에서 Add 또는 Done을 호출하면 안되며, Add 호출이없는 경우 goroutine은 Done을 호출하면 안됩니다.

결코 종료되지 않는 복수 for 개의 루프가있는 것처럼 보입니다. 조건이없고 break이 없습니다.

채널을 훨씬 더 간단하게 반복 할 수도 있습니다. 당신은 같은 구조 대체 할 수와

for { 
    file := <-channelOne 

을 간단한 :

for file := range channelOne { 

이것은 당신이 이상까지하고있는 채널이 닫혀있을 때, 루프가 사용할 수 있도록 종료됩니다 있다는 추가적인 장점이있다 소비자가 멈출 수있는 신호로 채널을 닫습니다.