자습서를 둘러 보려고했는데 웹 크롤러가 막혔습니다. 나는 그것을 끝냈다 고 생각했지만 결과는 일관성이 없었고 이유를 파악하기에 충분한 동시성 경험이 없습니다. 여기 웹 크롤러가 다른 출력으로 동일한 코드를 출력합니다.
package main
import (
"fmt"
"sync"
)
type Fetcher interface {
// Fetch returns the body of URL and
// a slice of URLs found on that page.
Fetch(url string) (body string, urls []string, err error)
}
var cache = struct {
fetched map[string]bool
sync.Mutex
}{fetched: make(map[string]bool)}
// Crawl uses fetcher to recursively crawl
// pages starting with url, to a maximum of depth.
func Crawl(url string, depth int, fetcher Fetcher, c chan []string, quit chan int) {
if depth <= 0 {
return
}
go safeVisit(url, c, quit, fetcher)
for {
select {
case <- quit:
return
case u:= <-c:
for _, v:= range u {
go Crawl(v, depth -1, fetcher, c, quit)
}
}
}
}
func main() {
c := make(chan []string)
quit := make(chan int)
Crawl("http://golang.org/", 4, fetcher, c, quit)
}
func safeVisit(url string, c chan []string, quit chan int, fetcher Fetcher) {
cache.Lock()
defer cache.Unlock()
if _, ok := cache.fetched[url] ; ok {
quit <- 0
return
}
body, urls, err := fetcher.Fetch(url)
cache.fetched[url] = true
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("Visited : %s, %q \n", url, body)
c <- urls
}
// fakeFetcher is Fetcher that returns canned results.
type fakeFetcher map[string]*fakeResult
type fakeResult struct {
body string
urls []string
}
func (f fakeFetcher) Fetch(url string) (string, []string, error) {
if res, ok := f[url]; ok {
return res.body, res.urls, nil
}
return "", nil, fmt.Errorf("not found: %s", url)
}
// fetcher is a populated fakeFetcher.
var fetcher = fakeFetcher{
"http://golang.org/": &fakeResult{
"The Go Programming Language",
[]string{
"http://golang.org/pkg/",
"http://golang.org/cmd/",
},
},
"http://golang.org/pkg/": &fakeResult{
"Packages",
[]string{
"http://golang.org/",
"http://golang.org/cmd/",
"http://golang.org/pkg/fmt/",
"http://golang.org/pkg/os/",
},
},
"http://golang.org/pkg/fmt/": &fakeResult{
"Package fmt",
[]string{
"http://golang.org/",
"http://golang.org/pkg/",
},
},
"http://golang.org/pkg/os/": &fakeResult{
"Package os",
[]string{
"http://golang.org/",
"http://golang.org/pkg/",
},
},
}
(위 의도적으로 별표에) 마지막으로
Visited : http://golang.org/, "The Go Programming Language"
not found: http://golang.org/cmd/
Visited : http://golang.org/pkg/, "Packages"
Visited : http://golang.org/pkg/os/, "Package os"
그리고 누락 된 최초의 마지막 패키지보다
Visited : http://golang.org/, "The Go Programming Language"
not found: http://golang.org/cmd/
Visited : http://golang.org/pkg/, "Packages"
Visited : http://golang.org/pkg/os/, "Package os"
**Visited : http://golang.org/pkg/fmt/, "Package fmt"**
Process finished with exit code 0
다른 일부 샘플 출력입니다 : 여기
내 코드입니다 심지어 일부 실행에서는 교착 상태가 발생합니다.Visited : http://golang.org/, "The Go Programming Language"
not found: http://golang.org/cmd/
Visited : http://golang.org/pkg/, "Packages"
Visited : http://golang.org/pkg/os/, "Package os"
Visited : http://golang.org/pkg/fmt/, "Package fmt"
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [select]:
main.Crawl(0x4bfdf9, 0x12, 0x4, 0x524220, 0xc420088120, 0xc420092000, 0xc420092060)
/home/kostas/development/challenges/go/helloWorld.go:26 +0x201
main.main()
/home/kostas/development/challenges/go/helloWorld.go:39 +0xab
goroutine 23 [select]:
main.Crawl(0x4bfdf9, 0x12, 0x3, 0x524220, 0xc420088120, 0xc420092000, 0xc420092060)
/home/kostas/development/challenges/go/helloWorld.go:26 +0x201
created by main.Crawl
/home/kostas/development/challenges/go/helloWorld.go:31 +0x123
goroutine 24 [select]:
main.Crawl(0x4c09f9, 0x16, 0x3, 0x524220, 0xc420088120, 0xc420092000, 0xc420092060)
/home/kostas/development/challenges/go/helloWorld.go:26 +0x201
created by main.Crawl
/home/kostas/development/challenges/go/helloWorld.go:31 +0x123
goroutine 5 [select]:
main.Crawl(0x4bfdf9, 0x12, 0x3, 0x524220, 0xc420088120, 0xc420092000, 0xc420092060)
/home/kostas/development/challenges/go/helloWorld.go:26 +0x201
created by main.Crawl
/home/kostas/development/challenges/go/helloWorld.go:31 +0x123
goroutine 6 [select]:
main.Crawl(0x4c0a0f, 0x16, 0x3, 0x524220, 0xc420088120, 0xc420092000, 0xc420092060)
/home/kostas/development/challenges/go/helloWorld.go:26 +0x201
created by main.Crawl
/home/kostas/development/challenges/go/helloWorld.go:31 +0x123
동시성 및 재귀와 관련이 있다고 가정합니다. 기다리는 그룹과 같은 것을 사용하는 git hub에서 다른 솔루션을 보았습니다.하지만 자습서에서는 사용되지 않았습니다. 지금까지 이동하여 아직 사용하지 않으려 고합니다. 내가 진행하고 문제에 작동되고 있는지 파악
UPDATE. 기본적으로 select 문은 채널이 종료되고 c가 항상 예상 된 순서대로 실행되지 않기 때문에 끝없는 루프에서 멈추게됩니다. 나는 print ("할 일이 없다")라는 기본 사례를 추가했으며 때로는 프로그램이 영원히 반복되어 가끔씩 올바른 방식으로 행운을 빕니다. 내 출구 조건이 올바르지 않습니다.
교착 상태는 얼마나 자주 발생합니까? 1에 10? 나는 그것을 재현하려고 노력하고있다. –
꽤 일관성이 없습니다. 경우에 따라 1/3 때때로 1/10/경우에 따라 –
이 특정 문제의 가장 일반적인 원인은 폐쇄되지 않는 채널입니다. 예를 들면 다음과 같습니다. https://stackoverflow.com/questions/12398359/throw-all-goroutines-are-asleep-deadlock- 나는 빈도를 측정하려고 노력하고 있으며 아마도 해결책을 제안 할 것입니다. 전문가는 아니므로 아무런 보장이 없습니다. –