我正在进行围棋之旅,我觉得除了并发性之外,我对这门语言有很好的理解。
幻灯片10是一个练习,要求读者并行化一个网络爬虫(并使其不覆盖重复,但我还没有做到。)
以下是我到目前为止的情况:
func Crawl(url string, depth int, fetcher Fetcher, ch chan string) {
if depth <= 0 {
return
}
body, urls, err := fetcher.Fetch(url)
if err != nil {
ch <- fmt.Sprintln(err)
return
}
ch <- fmt.Sprintf("found: %s %q\n", url, body)
for _, u := range urls {
go Crawl(u, depth-1, fetcher, ch)
}
}
func main() {
ch := make(chan string, 100)
go Crawl("http://golang.org/", 4, fetcher, ch)
for i := range ch {
fmt.Println(i)
}
}
我的问题是,在哪里我把关闭(ch)
调用。
如果我在Crawl
方法中的某个地方放置了defer close(ch)
,那么程序最终会从一个派生的goroutine写入一个闭合通道,因为对Crawl
的调用将在派生的goroutine执行之前返回。
如果我省略了对close(ch)
的调用,正如我所演示的那样,程序会在通道的主函数中死锁,因为当所有goroutine返回时,通道永远不会关闭。
o(1)在地图上查找url的时间,而不是在访问的所有url的切片上查找O(n),这应该有助于最大限度地减少关键部分内花费的时间,对于这个例子来说,这是一个微不足道的时间量,但会与规模相关。
WaitGroup用于阻止顶级Crawl()函数返回,直到所有子go例程完成。
func Crawl(url string, depth int, fetcher Fetcher) {
var str_map = make(map[string]bool)
var mux sync.Mutex
var wg sync.WaitGroup
var crawler func(string,int)
crawler = func(url string, depth int) {
defer wg.Done()
if depth <= 0 {
return
}
mux.Lock()
if _, ok := str_map[url]; ok {
mux.Unlock()
return;
}else{
str_map[url] = true
mux.Unlock()
}
body, urls, err := fetcher.Fetch(url)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("found: %s %q %q\n", url, body, urls)
for _, u := range urls {
wg.Add(1)
go crawler(u, depth-1)
}
}
wg.Add(1)
crawler(url,depth)
wg.Wait()
}
func main() {
Crawl("http://golang.org/", 4, fetcher)
}
我用了一个完全不同的方向。关于使用地图的提示可能误导了我。
// SafeUrlMap is safe to use concurrently.
type SafeUrlMap struct {
v map[string]string
mux sync.Mutex
}
func (c *SafeUrlMap) Set(key string, body string) {
c.mux.Lock()
// Lock so only one goroutine at a time can access the map c.v.
c.v[key] = body
c.mux.Unlock()
}
// Value returns mapped value for the given key.
func (c *SafeUrlMap) Value(key string) (string, bool) {
c.mux.Lock()
// Lock so only one goroutine at a time can access the map c.v.
defer c.mux.Unlock()
val, ok := c.v[key]
return val, ok
}
// Crawl uses fetcher to recursively crawl
// pages starting with url, to a maximum of depth.
func Crawl(url string, depth int, fetcher Fetcher, urlMap SafeUrlMap) {
defer wg.Done()
urlMap.Set(url, body)
if depth <= 0 {
return
}
body, urls, err := fetcher.Fetch(url)
if err != nil {
fmt.Println(err)
return
}
for _, u := range urls {
if _, ok := urlMap.Value(u); !ok {
wg.Add(1)
go Crawl(u, depth-1, fetcher, urlMap)
}
}
return
}
var wg sync.WaitGroup
func main() {
urlMap := SafeUrlMap{v: make(map[string]string)}
wg.Add(1)
go Crawl("http://golang.org/", 4, fetcher, urlMap)
wg.Wait()
for url := range urlMap.v {
body, _ := urlMap.Value(url)
fmt.Printf("found: %s %q\n", url, body)
}
}
查看一下有效Go的并行化部分,可以得出解决方案的想法。实际上,您必须关闭函数每个返回路径上的通道。实际上,这是一个很好的延迟语句用例:
func Crawl(url string, depth int, fetcher Fetcher, ret chan string) {
defer close(ret)
if depth <= 0 {
return
}
body, urls, err := fetcher.Fetch(url)
if err != nil {
ret <- err.Error()
return
}
ret <- fmt.Sprintf("found: %s %q", url, body)
result := make([]chan string, len(urls))
for i, u := range urls {
result[i] = make(chan string)
go Crawl(u, depth-1, fetcher, result[i])
}
for i := range result {
for s := range result[i] {
ret <- s
}
}
return
}
func main() {
result := make(chan string)
go Crawl("http://golang.org/", 4, fetcher, result)
for s := range result {
fmt.Println(s)
}
}
代码的本质区别是Crawl的每个实例都有自己的返回通道,调用者函数在其返回通道中收集结果。
我正在尝试解决围棋练习之旅,读者: 下面是我的解决方案: 它返回,这意味着只有第一个单词lbh penpxrq gur pbqr!是裂开的。我怎样才能破解整个句子?
问题内容: 我正在经历“ A Go of Go”,并且一直在编辑大多数课程,以确保我完全理解它们。我对以下练习的答案有疑问: https : //tour.golang.org/concurrency/10,可在此处找到: https //github.com/golang/tour/blob/master/solutions/ webcrawler.go 我对以下部分有疑问: 从通道添加和删除t
这是一个围棋学习免费软件。 本软件具有人机对局、双人对局、对局演示、对局打谱等功能,可选择2-19路棋盘对局,目前已有三步推算的棋力,可作为围棋初学者的辅助学习工具,也可作为围棋爱好者的辅助研究工具。 本软件采用易语言编写!易语言官方网址: http://www.dywt.com.cn http://www.eyuyan.com 版权所有(C) 2008-2009 梁远海 E-Mail: nply
你正在慢慢地构建我所说的个人流程实践(3P),这根本不是一个新的想法。3P 的目的是客观的洞察如何做事情,而避免杀死你的创造力和生产力。通过简单地跟踪小型指标和制作运行图来指导改进,你可以彻底改变你的工作状况。但是,这样做的风险在于,这会阻碍你快速入侵黑客或完成任务,或者你的 3P 的工作量将比你的实际工作更多。 在我的编程生涯中,我这样做了大约四年,并且它很好地让我认识到我自己和我的工作方式。它
本文向大家介绍开启BootStrap学习之旅,包括了开启BootStrap学习之旅的使用技巧和注意事项,需要的朋友参考一下 本文总结了Bootstrap之所以广泛流传的11大原因。如果你还没有使用Twitter Bootstrap,建议你去了解一下。我也是最近才有所发现的,不过有更好的消息,在前两天微软发布的VS2013正式版中,也已经将BootStrap3.0的版本加入了额,连微软都看到boot
为魅族M8手机开发的围棋打谱软件,还在开发过程中,目前功能不全,但基本功能可用。现在仅支持SGF格式的围棋棋谱。基本功能:打开并解析SGF棋谱,单步向前向后,落子音效,自动提子,显示棋局信息和解说,支持自定义皮肤。