- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我一直在努力完成所有的 go 教程之旅,但我被困在了 the web crawler exercise 上。 .
我以为我完成了,但是输出不一致,我没有足够的并发经验来弄清楚为什么。
Here's我的代码:
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/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/, "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
我假设它与并发和递归有关。我在 github 中看到了其他使用 WaitGroups 等的解决方案,但到目前为止还没有在 go 之旅中使用它,所以我宁愿不使用它。
更新
我弄清楚了正在发生的事情并正在解决这个问题。基本上有时 select 语句会陷入无限循环,因为 channel 退出和 c 并不总是按预期顺序执行。我添加了一个打印(“无事可做”)的默认情况,程序有时会永远循环,有时会以正确的方式幸运地执行。我的退出条件不对
最佳答案
我认为情况很清楚。你的 channel 一团糟。多个 goroutines 从同一个 channel 接收,golang 只是随机选择一个。
当你通过 quit
发送一个零时,你永远不知道哪个 goroutine 退出了:它是由 go sheduler 随机选择的。新生成的 Crawl 有可能在从 c
接收到之前从 quit
接收到(即使两个 channel 都已准备好)。
因此,depth
是一团糟,它使调用 safeVisit
的次数不稳定,导致 quit
发出不同的(随机的) ) 信号。有时仅仅退出所有生成的 goroutine 是不够的,这是一个死锁。
编辑:
首先你应该明白你的任务是什么。 Crawl
函数接收一个 url、一个 dep 和一个 fetcher,它:
dep-1
从获取的 url 生成新的 Crawl
队列虽然tour要求你并行“fetch”url,但是很明显step 2和step 3必须在step 1之后发生,也就是说单次Crawl等待fetch是正常的。这意味着,不需要新的 goroutine 来调用 Fetch
。
并且在第 3 步,每个新的 Crawl
调用都无需等待前一个完成,因此这些调用应该是并行的。
通过这些分析,可以得到这些代码:
func Crawl(url string, depth int, fetcher Fetcher) {
// TODO: Fetch URLs in parallel.
// TODO: Don't fetch the same URL twice.
// This implementation doesn't do either:
if depth <= 0 {
return
}
body, urls, err := fetcher.Fetch(url)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("found: %s %q\n", url, body)
for _, u := range urls {
go Crawl(u, depth-1, fetcher)
}
return
}
还有一个问题:处理访问过的 url。你做的很好,不是发送一个quit
,而是让它成为func(string) bool
并直接调用它:if Visited(Url) { return }
完成。
旁注:游览真的不擅长教授并发性。您可能想查看 go 博客文章,例如 golang 并发模式或通过通信共享内存。
关于去旅游#10 : Lost in concurrency,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48042992/
我正在尝试在我的项目中使用 Knockout Concurrency 插件,目前我正在摆弄示例代码,但我没有让它工作: https://github.com/AndersMalmgren/Knocko
我正在尝试使用 grunt 运行多个监视任务,但似乎无法运行。我正在使用 grunt concurrent,但它似乎只运行我指定的一部分任务,只是短暂停止。 这是我的 gruntfile 的片段: c
我有一个使用 Grunt 的 Ionic 项目,它是由 Yeoman 构建的。我设法将其配置为在运行 Fedora 22 的本地计算机上正常工作。 目前,我正在尝试在 Centos 7 服务器实例上配
关闭。这个问题需要debugging details .它目前不接受答案。 想改进这个问题?将问题更新为 on-topic对于堆栈溢出。 1年前关闭。 Improve this question Co
Go is a concurrent lang 这是什么意思? 这是否意味着它是 C/C++/Java.. 的替代品? 最佳答案 A concurrent language是一种具有并发语言结构的语言
我正在尝试使用 Kafka 实现一个事件溯源系统,但遇到了以下问题。在新用户注册期间,我想检查用户提供的用户名是否已被使用。但是,请考虑 2 个用户尝试同时注册提供相同用户名的情况。 根据我对 ES
我正在完成 golang 之旅并进行最后的练习,将网络爬虫更改为并行爬行而不是重复爬行 (http://tour.golang.org/#73)。我只更改了抓取功能。 var used = m
ruby 版本 2.5.3 当我输入 rails new upload_app 时,出现以下错误 错误如下 Traceback (most recent call last): 39: fro
func main() { jobs := []Job{job1, job2, job3} numOfJobs := len(jobs) resultsChan := make
我正在尝试在 Rust async-await(即将稳定)中同时(而不是按顺序)运行 futures 列表,直到它们中的任何一个解析为 true . 想象一下有一个 Vec ,以及为每个文件运行的 f
当我看到这段代码时出现了问题: private static volatile ConcurrentHashMap cMap = null; static { cMap = new Concu
刚在lab环境下安装dcos环境,在centos7 linux机器上尝试安装dcos客户端时得到 **[root@rmavmdock5 dcos]# bash install.sh . http://
为什么要为 Scala fork ForkJoinPool? 哪种实现方式和哪种情况更受欢迎? 最佳答案 scala 库拥有自己的 ForkJoinPool 副本的明显原因是 scala 必须在 1.
是的,我知道。关于 NSOperation 世界有很多问题和答案,但我仍然有一些疑问。我会尝试用两部分的问题来解释我的疑虑。它们相互关联。 在 SO 帖子中 nsoperationqueue-and-
我将 Play Framework 2.1.1 与一个生成 java.util.concurrent.Future 结果的外部 java 库一起使用。我使用的是 scala future 而不是 Ak
我们使用 Doug Lea 的并发库已有 8 年多了。出于向后兼容性的原因,我们的代码仅限于使用 Java 2 语言级别和 JDK 1.3 库。 现在我们正在开发一个主要的新版本,并最终能够使用 Ja
此问题涉及当 saga 数据保留在 Azure 表存储中时对 saga 数据的并发访问。它也是在 Prefer 的文档中找到的引用信息:http://docs.particular.net/nserv
我有一个创建锁的方法。 ReadWriteLock lock = new ReentrantReadWriteLock(); 然后我使用 Lock Interface 将该对象传递到一个方法中。 m
当我在 Mac OSX 命令行上的 python 中执行以下操作时: >>> from concurrent.futures import ProcessPoolExecutor 我明白了 Modul
我正在 listview 的线程池上创建异步任务。我正在通过 asynchtask 的 listarray 处理这些任务。当 fragment 被销毁时我必须删除这些任务,并且当我在销毁最后一个 fr
我是一名优秀的程序员,十分优秀!