2017-10-14 8 views
0

다음은이 solution입니다. 경쟁 탐지기를 실행할 때 탐지 된 경쟁 조건이 없습니다. Golang 웹 크롤러 솔루션, 2 데이터 레이스, 종료 상태 66

================== WARNING: DATA RACE Read at 0x00c42006c1e0 by goroutine 6: main.Crawl.func1() /task2.go:50 +0x53

Previous write at 0x00c42006c1e0 by main goroutine: main.Crawl() /task2.go:48 +0x692 main.main() /task2.go:66 +0x8c

Goroutine 6 (running) created at: main.Crawl() /task2.go:49 +0x61e main.main() /task2.go:66 +0x8c ================== . . . ================== WARNING: DATA RACE Read at 0x00c420094070 by goroutine 8: main.Crawl.func1() /task2.go:50 +0x53

Previous write at 0x00c420094070 by goroutine 6: main.Crawl() /task2.go:48 +0x692 main.Crawl.func1() /task2.go:51 +0x240

Goroutine 8 (running) created at: main.Crawl() /task2.go:49 +0x61e main.Crawl.func1() /task2.go:51 +0x240

Goroutine 6 (running) created at: main.Crawl() /task2.go:49 +0x61e main.main()

/task2.go:66 +0x8c

Found 2 data race(s) exit status 66

다음

내 코드, 내가 잘못된거야 어디 사람이 나에게 알려 주시기 바랍니다 수 있습니다 : 난 내 코드와 경주 detecter를 실행할 때 다음과 같은 오류를 제공합니다. 나는 오랫동안 그것을 알아 내려고 노력했지만 식별 할 수 없었다. 당신은 재귀하는 이동 루틴을 발사 크롤링를 호출하고

 var visited = struct { 
     urls map[string]bool 
     sync.Mutex 
    }{urls: make(map[string]bool)} 

    func Crawl(url string, depth int, fetcher Fetcher) { 

     if depth <= 0 { 
      return 
     } 

     visited.Lock() 
     if visited.urls[url] && visited.urls[url] == true { 
      fmt.Println("already fetched: ", url) 

      visited.Unlock() 
      return 
     } 
     visited.urls[url] = true 
     visited.Unlock() 

     body, urls, err := fetcher.Fetch(url) 

     if err != nil { 
      fmt.Println(err) 
      return 
     } 
     done := make(chan bool) 

     for _, nestedUrl := range urls { 
      go func(url string, d int) { 
       fmt.Printf("-> Crawling child %v of %v with depth %v \n", nestedUrl, url, depth) 
       Crawl(url, d, fetcher) 
       done <- true 

      }(nestedUrl, depth-1) 
     } 
     for i := range urls { 
      fmt.Printf("<- [%v] %v/%v Waiting for child %v.\n", url, i, len(urls)) 
      <-done 
     } 
     fmt.Printf("<- Done with %v\n", url) 
    } 

    func main() { 
     Crawl("http://golang.org/", 4, fetcher) 

     fmt.Println("Fetching stats\n--------------") 

     for url, err := range visited.urls { 
      if err != true { 
       fmt.Printf("%v failed: %v\n", url, err) 
      } else { 
       fmt.Printf("%v was fetched\n", url) 
      } 
     } 
    } 
+0

전체 파일을 표시 할 수 있습니까? play.google.com 또는 github에 게시 할 수 있나요? 이제 경주가 공황 상태에 빠져있는 곳이 어디인지는 분명하지 않습니다. –

+0

아마도 자식 goroutine'Printf' 호출에서'nestedUrl'을 * 사용했을 것입니다. –

+0

전체 파일을 공유하지 않으면 어떤 줄이 실패했는지 알 수 없습니다. –

답변

0

는, 당신은 보호 된지도가 일부 마무리를 크롤링하기 전에 실행되는 주에 뮤텍스없이 방문에 접근하고 있습니다. 스타일에 대한 몇 가지 포인트 :

  • 완료를 기다리는 (공용 잠금)
  • 사용 대기 그룹 또는 주에 채널을 고정하지 담당에 방문 구조체를 넣고 동기 API를 선호

동기가 시작되면 비동기로 변경하는 것이 가장 좋은 방법을 찾아야합니다. 그런 다음 동기 크롤링 기능을 시작하기 만하면 동기화 할 수 있습니다. 원래 투어를 살펴보면이 솔루션과 매우 유사하지 않으므로이를 따라 할 훌륭한 모델인지 확신 할 수 없습니다. 발신자는 인종에 관해서 자물쇠를하거나 걱정할 필요가 없어야하므로 재 설계해야합니다. original tour exercise에서 다시 시작하겠습니다.

잠금, 나는

type T struct { 
data map[string]bool 
mu sync.Mutex // not just sync.Mutex 
} 

을 사용하십시오 및 잠금이 필요한 데이터의 상태를 조정하거나 검색 할 수있는 기능이 때 T 결정합니다. 이렇게하면 Lock을 사용하는 것이 더 간단 해지고 실수를하지 않게됩니다.

+0

Kenny에게 감사드립니다. "동기 API 선호" 그게 무슨 뜻입니까? 내 말은 내가 이미 동 기적으로 수행하려한다는 뜻이다. "방문한 구조체를 잠금 (공개 잠금 없음)으로 지정" 예제를 보여 주시겠습니까? "완료 대기를 위해 대기중인 대기 그룹 또는 채널 사용" 이미 모든 이동 루틴 완료 대기를 위해 채널을 사용 중입니다. –

+0

go 키워드를 사용하려는 경우 비동기 버전이 아닌 것으로 작성하십시오. 이것은 특별한 경우이지만 일반적으로 호출자는 비동기 호출 여부를 결정합니다. go 키워드를 사용하여 동기화를 비동기로 변환 할 수 있지만 동기화를 위해 비동기로 변환 할 수는 없습니다. 그런 다음 호출 수신자가 데이터를 잠글 때를 결정합니다. 잠글 필요가있을 경우 기능 외부에서 맵을 사용하지 않거나 잠금 기능을 노출하십시오. –