求问《GO 语言圣经》里这句话应该怎么解释?

2021-04-02 09:10:34 +08:00
 yuantingwuji

下面这段代码来自《 GO 语言圣经》 8.6. 示例: 并发的 Web 爬虫

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
            }
        }
    }
}

书里面说,“crawl 函数爬到的链接在一个专有的 goroutine 中被发送到 worklist 中来避免死锁”,就是上面代码中加了中文注释那一行,为什么不把 worklist <- foundLinks 这个操作加入专有协程就有引起死锁呢?

3592 次点击
所在节点    Go 编程语言
11 条回复
iceheart
2021-04-02 09:20:03 +08:00
就是单一协程程服务的模式代替临界区访问的模式
ihipop
2021-04-02 09:28:18 +08:00
一楼说的高大上,单纯从代码看,中文注释处这是把结果发送给 work list,但是 worklist 可能是满的,如果读取 work list 的那边读取慢或者不读取,爬取协程就被阻塞在写入 work list chan 那边了,把发送行为放到子协程就不影响爬取协程继续爬取。
ihipop
2021-04-02 09:36:33 +08:00
@ihipop 然后
main 函数末尾会把所有未爬取过的连接过滤一遍,再发给 unseenlinks,如果直接把 foundlinks 发现的链接直接给 crawl 爬取,那么这里可能存在重复的链接,爬虫就会陷入死循环了。
yuantingwuji
2021-04-02 09:45:58 +08:00
@ihipop 噢,我好像明白了,如果 worklist <- foundLinks 操作不加入专有协程,则会阻塞 unseenLinks 这个变量的读取,这样会进一步阻塞主协程 unseenLinks 的接收操作,进而阻塞主协程 worklist 的的读取,这样就形成死锁了。
yeqown
2021-04-02 09:53:08 +08:00
unseenLinks 和 worklist 在阻塞情况下互相等待,就会出现死锁
mogg
2021-04-02 10:52:46 +08:00
考虑 unseenLinks 和 worklist 都满了的情况,worklist <- foundLinks, unseenLinks <- link 都阻塞,这时候就死锁了
treblex
2021-04-02 11:21:16 +08:00
跑个题,为啥接收命令行参数也要开个协程
VincentYe123
2021-04-02 11:40:58 +08:00
@treblex 和上面的回答的原因一样
kkbblzq
2021-04-02 12:21:38 +08:00
@treblex 因为是无缓冲区的 chan,原因还是和上面一样
hq136234303
2021-04-02 14:34:41 +08:00
@ihipop 这样回照成携程的无限上涨
renoyuan
2021-04-09 14:33:00 +08:00
《 GO 语言圣经》这本书中文版有有一种偷工减料的感觉。是我找的版本不对吗: https://books.studygolang.com/gopl-zh/

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/767415

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX