```
func main() {
worklist := make(chan []string) // lists of URLs, may have duplicates
unseenLinks := make(chan string) // de-duplicated URLs
// Add command-line arguments to worklist.
go func() { worklist <- os.Args[1:] }()
// Create 20 crawler goroutines to fetch each unseen link.
for i := 0; i < 20; i++ {
go func() {
for link := range unseenLinks {
foundLinks := crawl(link)
go func() { worklist <- foundLinks }()
}
}()
}
// The main goroutine de-duplicates worklist items
// and sends the unseen ones to the crawlers.
seen := make(map[string]bool)
for list := range worklist {
for _, link := range list {
if !seen[link] {
seen[link] = true
unseenLinks <- link
}
}
}
}
```
主要问题:**书中源代码如上所示,求问第13行代码,`go func(){worklisk <- foundLinks}()`,书中说非得要这个才能避免死锁,为甚么一定要新开一个goroutine才能避免?直接 `worklist <- foundlinks`,不新创goroutine我跑了,没有报dead lock, 但是运行的速度变慢了,**
我自己思路如下,像上面的代码, 创建20个协程和创建1个携程在死锁的问题上没影响
抽出来代码的结构就是有两个通道, ch1, ch2。 两个类型的goroutine, gorou1, gorou2,
一个goroutine从一个channel 取值发送到另外一个,
可以理解为gorou1从ch1接收值,再发送到ch2。gorou2从ch2拿值,发送到ch1, 如下,
这种方式不需要在往ch2发送值时,添加一个协程来避免死锁, 能直接跑通
```go
func main(){
ch1 := make(chan int)
ch2 := make(chan int)
go func(){ ch1 <- 1 }()
go func() {
for x:= range ch1 {
ch2 <- x
fmt.Println("ch1")
}
}()
for x:= range ch2 {
ch1 <-x
fmt.Println("ch2", c)
}
}
```
是我哪里的理解有问题?
可以看下最近的go周刊里面的题目:https://studygolang.com/topics/12982
原因:假设我们在main goroutine里启动一个子goroutine叫b,那么实际上在main goroutine里发生的事情是这样的:
1.main goroutine执行到go语句
2.go语句发现后面的函数表达式需要传递参数
3.于是被传递的参数在main goroutine里求值
4.新的goroutine b被创建,刚求值的参数传递给需要执行的函数(假设叫f),f在goroutine b中开始执行
5.go语句结束,控制流程回到main goroutine
所以go fmt.Println(<-ch1)里的chan接收操作是在main goroutine里执行的,因此死锁是板上钉钉的事情。如果改成go func() {fmt.Println(<-ch1)}就没问题了
#1