gpt4 book ai didi

go - 一例 `all goroutines are asleep - deadlock!`我不知道为什么

转载 作者:行者123 更新时间:2023-12-01 21:22:01 26 4
gpt4 key购买 nike

TL; DR:all goroutines are asleep, deadlock!的一种典型情况,但无法弄清

我正在解析Wiktionary XML转储以构建单词数据库。我将每篇文章的文本解析推迟到一个goroutine,希望它可以加快处理速度。
它是7GB,并且在串行方式下在我的计算机中处理时间不到2分钟,但是如果我可以利用所有内核,那为什么不行。

我是线程一般的新手,出现了all goroutines are asleep, deadlock!错误。
怎么了

这可能根本不起作用,因为它使用了无缓冲的 channel ,因此所有goroutine最终都有效地串行执行,但是我的想法是学习和理解线程并使用不同的替代方法测试它需要花费多长时间:

  • 无缓冲 channel
  • 不同大小的缓冲 channel
  • 一次仅调用与runtime.NumCPU()一样多的goroutines

  • 我的伪代码摘要:
    while tag := xml.getNextTag() {
    wg.Add(1)
    go parseTagText(chan, wg, tag.text)

    // consume a channel message if available
    select {
    case msg := <-chan:
    // do something with msg
    default:
    }
    }
    // reading tags finished, wait for running goroutines, consume what's left on the channel
    for msg := range chan {
    // do something with msg
    }
    // Sometimes this point is never reached, I get a deadlock
    wg.Wait()

    ----

    func parseTagText(chan, wg, tag.text) {
    defer wg.Done()
    // parse tag.text
    chan <- whatever // just inform that the text has been parsed
    }

    完整的代码:
    https://play.golang.org/p/0t2EqptJBXE

    最佳答案

    在Go Playground上的完整示例中,您:

  • 创建一个 channel (第39行,results := make(chan langs))和一个 WaitGroup (第40行,var wait sync.WaitGroup)。到目前为止,一切都很好。
  • 循环:在循环中,有时会剥离任务:
                if ...various conditions... {
    wait.Add(1)
    go parseTerm(results, &wait, text)
    }
  • 在循环中,有时从 channel 中进行非阻塞读取(如您的问题所示)。这里也没问题。但是...
  • 在循环的最后,使用:
    for res := range results {
    ...
    }

    在所有作者写完之后,再也不需要在一个地方调用close(results)了。此循环使用从 channel 读取的阻塞。只要某些编写程序goroutine仍在运行,阻塞读取就可以在不停止整个系统的情况下进行阻塞,但是当最后一个编写程序完成写入并退出时,将没有剩余的编写程序goroutine。其余的goroutine可能会救您,但没有。

  • 由于您正确使用了 var wait(在正确的位置添加1,然后在编写器的正确位置调用 Done()),因此解决方案是再添加一个goroutine,这将是一种抢救您的方法:
    go func() {
    wait.Wait()
    close(results)
    }()

    您应该在进入 for res := range results循环之前就剥离此救援程序goroutine。 (如果您更早地将其分离,则可能会看到 wait变量计数到零的时间太早,就在通过拆分另一个 parseTerm将其重新计数之前)。

    这个匿名函数将阻塞 wait变量的 Wait()函数,直到最后一个编写程序goroutine调用了最终的 wait.Done()为止,这将取消阻塞此goroutine。然后,此goroutine将调用 close(results),它将安排 for goroutine中的 main循环完成,从而取消对该goroutine的阻塞。当此goroutine(救援人员)返回并因此终止时,不再有救援人员,但我们不再需要任何救援人员。

    (然后,此主代码会不必要地调用 wait.Wait():由于直到新goroutine中的 for已被解除阻止之前 wait.Wait()才终止,所以我们知道下一个 wait.Wait()将立即返回。因此,我们可以丢弃第二个调用,尽管将其留在无害)

    关于go - 一例 `all goroutines are asleep - deadlock!`我不知道为什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59432608/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com