首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >解决方案,2个数据竞赛,退出状态66

解决方案,2个数据竞赛,退出状态66
EN

Stack Overflow用户
提问于 2017-10-14 21:26:45
回答 1查看 192关注 0票数 0

我一直在跟踪这个解决方案。当我运行种族检测仪时,没有检测到种族状况。但是,当我使用代码运行种族检测器时,它会出现以下错误:

==================警告:由goroutine 6: main.Crawl.func1() /task2.go:50 +0x53在0x00c42006c1e0读取数据竞赛 以前在0x00c42006c1e0上由主goroutine编写: main.Crawl() /task2.go:48 +0x692 main.main() /task2.go:66 +0x8c Goroutine 6(运行)创建于: main.Crawl() /task2.go:49 +0x61e main.main() /task2.go:66 +0x8c ==================。。。==================警告:戈鲁廷8: main.Crawl.func1() /task2.go:50 +0x53在0x00c420094070处读取数据竞赛 戈鲁廷在0x00c420094070上的前写: main.Crawl() /task2.go:48 +0x692 main.Crawl.func1() /task2.go:51 +0x240 Goroutine 8(运行)创建于: main.Crawl() /task2.go:49 +0x61e main.Crawl.func1() /task2.go:51 +0x240 Goroutine 6(运行)创建于: main.Crawl() /task2.go:49 +0x61e main.main() /task2.go:66 +0x8c 发现2个数据竞争退出状态66

下面是我的代码,有人能告诉我哪里出错了吗?我想弄清楚这件事已经很长时间了,但我无法辨认。

代码语言:javascript
复制
        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)
            }
        }
  }
EN

回答 1

Stack Overflow用户

发布于 2017-10-15 06:07:58

您正在调用crawls,这将触发一个go例程以递归,然后您将访问访问过的受保护的映射,而main中没有互斥,在某些爬行完成之前执行。关于风格的几点看法:

  • 更喜欢同步api
  • 让访问的结构负责锁定(没有公共锁)
  • 在main中使用等待组或通道等待完成。

因此,启动同步,然后找出如何最好地更改为异步。然后,只需将go放在同步爬行函数的前面,就可以使其成为同步。从最初的巡回演出来看,它并不太像这个解决方案,所以我不确定这是一个很好的模型来遵循。调用者不应该锁定或担心种族,所以您需要重新设计。我会从原始旅游锻炼重新开始。

为了锁,我会用

代码语言:javascript
复制
type T struct {
data map[string]bool
mu sync.Mutex // not just sync.Mutex
}

T决定何时需要锁定,并具有调整数据状态或搜索数据的功能。这使得考虑使用锁变得更简单,并且减少了出错的可能性。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46749498

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档