在这本书中,有几次谈到deadlock关于goroutine和channel的错误用法,而我未能理解为什么会出现死锁。
我想说的第一件事是,我知道通道发送和接收会阻塞,直到有项目需要阅读或房间发送项目,也许这是一些deadlock的深层原因。但请根据这本书的以下摘录给我一些解释:
第240页
此代码用于并发爬行urls,BFS样式:
func main() {
worklist := make(chan []string)
// Start with the command-line arguments.
go func() { worklist <- os.Args[1:] }()
// Crawl the web concurrently.
seen := make(map[string]bool)
for list := range worklist {
for _, link := range list {
if !seen[link] {
seen[link] = true
go func(link string) {
worklist <- crawl(link)
}(link)
}
}
}
}引用书的第二段:
...the将命令行参数初始发送到工作列表必须在自己的goroutine中运行,以避免死锁,在这种情况下,主goroutine和爬虫goroutine都试图相互发送,而两者都没有收到.
假设初始发送到worklist的不是在它自己的goroutin中,我想它的工作方式如下:
worklist,阻塞直到收到for range接收初始项,因此取消阻塞worklist通道worklist,循环..。所以据我所知,它不会阻塞和死锁。我哪里错了?
UPDATE:@mkopriva帮助我认识到步骤1被阻止,步骤2,3无法到达。所以这件事我很清楚。
第243页
这种死锁情况可能与第240页中的情况相同:
func main() {
worklist := make(chan []string) // list of URLs, may have duplicates
unseenLinks := make(chan string) // de-duplicated URLs
// Add command-lin 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
}
}
}
}因此,如果我将省略go放在for-range循环中,那么死锁是如何发生的?
发布于 2021-09-15 07:12:27
在第一个片段中,初始通道发送需要在goroutine中完成,因为如果没有goroutine,语句将无限期地阻塞,执行将永远不会到达从该通道接收到的循环。也就是说,要从1.到2.,1.需要在一段时间内完成。但是,如果1.阻塞,则永远不会到达2.。
从注释开始的位置是执行停止的位置:
func main() {
worklist := make(chan []string)
worklist <- os.Args[1:]
//
// seen := make(map[string]bool)
// for list := range worklist {
// for _, link := range list {
// if !seen[link] {
// seen[link] = true
// go func(link string) {
// worklist <- crawl(link)
// }(link)
// }
// }
// }
// }在第二个片段中,在通道上有一个for-range循环,这样的循环在远程通道关闭之前不会退出。这意味着,虽然这样一个循环的主体可能会继续被执行,但后面的循环之后的代码将永远无法到达。
从注释开始的位置是执行停止的位置:
func main() {
worklist := make(chan []string)
unseenLinks := make(chan string)
go func() { worklist <- os.Args[1:] }()
for i := 0; i < 20; i++ {
for link := range unseenLinks {
// foundLinks := crawl(link)
// go func() { worklist <- foundLinks }()
// }
// }
//
// seen := make(map[string]bool)
// for list := range worklist {
// for _, link := range list {
// if !seen[link] {
// seen[link] = true
// unseenLinks <- link
// }
// }
// }
// }发布于 2022-04-29 08:09:14
在第二个片段中,我认为作者正在下面讨论go例程:
go func() { worklist <- foundLinks }()爬行找到的链接从专用的goroutine发送到工作列表,以避免死锁。
为什么这必须存在?
https://stackoverflow.com/questions/69187584
复制相似问题