首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >死锁在书<围棋编程Language>,它将如何发生,为什么会发生?

死锁在书<围棋编程Language>,它将如何发生,为什么会发生?
EN

Stack Overflow用户
提问于 2021-09-15 05:37:04
回答 2查看 103关注 0票数 0

在这本书中,有几次谈到deadlock关于goroutinechannel的错误用法,而我未能理解为什么会出现死锁。

我想说的第一件事是,我知道通道发送和接收会阻塞,直到有项目需要阅读或房间发送项目,也许这是一些deadlock的深层原因。但请根据这本书的以下摘录给我一些解释:

第240页

此代码用于并发爬行urls,BFS样式:

代码语言:javascript
复制
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中,我想它的工作方式如下:

  1. 主goroutine发送初始到worklist,阻塞直到收到
  2. for range接收初始项,因此取消阻塞worklist通道
  3. 爬虫猩猩把它的物品发送到worklist,循环..。

所以据我所知,它不会阻塞和死锁。我哪里错了?

UPDATE:@mkopriva帮助我认识到步骤1被阻止,步骤2,3无法到达。所以这件事我很清楚。

第243页

这种死锁情况可能与第240页中的情况相同:

代码语言:javascript
复制
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循环中,那么死锁是如何发生的?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-09-15 07:12:27

在第一个片段中,初始通道发送需要在goroutine中完成,因为如果没有goroutine,语句将无限期地阻塞,执行将永远不会到达从该通道接收到的循环。也就是说,要从1.2.1.需要在一段时间内完成。但是,如果1.阻塞,则永远不会到达2.

从注释开始的位置是执行停止的位置:

代码语言:javascript
复制
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循环,这样的循环在远程通道关闭之前不会退出。这意味着,虽然这样一个循环的主体可能会继续被执行,但后面的循环之后的代码将永远无法到达。

范围

  1. 对于通道,生成的迭代值是在通道上发送的连续值,直到通道是 关着的不营业的。如果通道为零,则范围表达式将永远阻塞。

从注释开始的位置是执行停止的位置:

代码语言:javascript
复制
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
//             }
//         }
//     }
// }
票数 3
EN

Stack Overflow用户

发布于 2022-04-29 08:09:14

在第二个片段中,我认为作者正在下面讨论go例程:

代码语言:javascript
复制
go func() { worklist <- foundLinks }()

爬行找到的链接从专用的goroutine发送到工作列表,以避免死锁。

为什么这必须存在?

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69187584

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档