我正在练习通过同时将计算分成 100 个组来计算阶乘的挑战,我在 WaitGroups 上解决了很多问题,但仍然在函数中calculateFactorial我在通道部分的范围上遇到了死锁。希望有人能指出这里的问题,谢谢。更新:它通过简单地将 更改为缓冲通道解决了上述代码中的问题。你永远不应该仅仅为了修复死锁而添加缓冲。如果您的程序死锁,从零缓冲开始并仔细考虑依赖关系,修复起来要容易得多。然后在您知道不会死锁时添加缓冲。那么谁能帮我弄清楚如何不为此使用缓冲通道?是否可以?此外,我对导致死锁的确切原因做了一些研究。如果通道是无缓冲的,则发送方会阻塞,直到接收方收到该值。如果通道有缓冲区,发送方只会阻塞直到值被复制到缓冲区;如果缓冲区已满,这意味着等待某个接收者检索到一个值。否则说:当通道已满时,发送方等待另一个 goroutine 通过接收来腾出一些空间你可以看到一个无缓冲的通道总是满的:必须有另一个 goroutine 来接收发送者发送的内容。所以在我原来的情况下,可能导致僵局的原因可能是:频道上的范围没有接收到?通道上的范围未在单独的 go 例程中接收。?没有oneResult正确关闭,所以 range over channel 不知道尽头在哪里?对于数字 3,我不知道关闭 before range over 是否有任何错误oneResult,因为这种模式出现在互联网上的许多示例中。如果是 3 号,是不是等待组有问题?我得到了另一篇与我的情况非常相似的文章,他使用for { select {} }无限循环作为 range over 的替代方法,似乎解决了他的问题。go func() { for{ select { case p := <-pch: findcp(p) } } }()第 2 课 — 无缓冲通道无法保存值(是的,它就在名称“无缓冲”中),因此无论发送到该通道的什么,都必须立即由其他代码接收。接收代码必须在不同的 goroutine 中,因为一个 goroutine 不能同时做两件事:它不能发送和接收;它必须是一个或另一个。
2 回答
慕哥9229398
TA贡献1877条经验 获得超6个赞
死锁不在 range-over-channel 循环上。如果您在操场上运行代码,您会在堆栈跟踪的顶部看到错误是由wg2.Wait
(操场上的第 88 行并由堆栈跟踪指向)引起的。同样在堆栈跟踪中,您可以看到所有因死锁而未完成的 goroutine,这是因为oneResult<-t
从未完成,因此循环中启动的 goroutine 都没有完成。
所以主要问题在这里:
wg2.Wait()
close(oneResult)
// ...
for n := range oneResult{
// ...
我想,在封闭的频道上循环也不是你想要的。但是,即使您没有关闭频道,该循环也永远不会开始,因为wg2.Wait()
它会等到完成。
oneResult <- t wg2.Done()
但它永远不会完成,因为它依赖于已经运行的循环。该线路oneResult <- t
不会完成,除非另一侧有人从该通道接收信号,这是您的循环,但是该通道范围循环仍在等待完成wg2.Wait()
。
所以本质上你在通道的发送者和接收者之间有一个“循环依赖”。
要解决此问题,您需要允许循环开始从通道接收数据,同时仍确保该通道在完成后关闭。你可以通过将两条等待和关闭线包装到它们自己的 goroutine 中来做这件事。
https://play.golang.com/p/rwwCFVszZ6Q
- 2 回答
- 0 关注
- 114 浏览
添加回答
举报
0/150
提交
取消