我得到了“致命的错误:所有的goroutines都睡着了 - 僵局! “由于某些原因,在下面的代码中。我使用缓冲通道,应该是非阻塞的。不确定我做错了什么
/**
* Returns a HashSet of the string permutation.
*
* @param prefix an empty string.
* @param str the string to create perm.
* @return permutations a HashSet of the permutation.
*/
private static HashSet<String> permutation(String prefix, String str) {
HashSet<String> permutations = new HashSet<String>();
int n = str.length();
if (n == 0) {
permutations.add(prefix);
} else {
for (int i = 0; i < n; i++) {
permutations.addAll(permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i + 1, n)));
}
}
return permutations;
}
答案 0 :(得分:1)
虽然您的解决方案可行,但我对此并不满意。
首先,您需要更改通道大小以使其正常工作这一事实表明存在潜在的问题/错误。现在,每当您想要发布另一个doSomething
时,您必须记住更改频道的长度。
其次,你要等到所有goroutine完成才能从频道中读取。这是一种浪费&#34;作为通道上的范围循环的一个要点是,您不必等到生成所有项目(写入通道),您可以在其中一些项目准备好后立即开始处理这些项目。
所以我会把你的代码写成类似
的代码func main() {
c := make(chan int)
var wg sync.WaitGroup
wg.Add(3)
go func() {
doSomething(c)
defer wg.Done()
}()
go func() {
doSomething(c)
defer wg.Done()
}()
go func() {
doSomething(c)
defer wg.Done()
}()
go func() {
wg.Wait()
defer close(c)
}()
for v := range c {
fmt.Print(v)
}
}
func doSomething(c chan<- int) {
c <- 1
}
https://play.golang.org/p/T3dfiztKot
请注意等待和关闭频道现在如何在其自己的goroutine中 - 这允许立即开始遍历频道(现在是无缓冲的!)。
我还更改了代码,以便WaitGroup
永远不会离开声明它的范围(即它不被用作参数),这是我个人的偏好。我相信它使代码更容易理解。
答案 1 :(得分:0)
我发现了问题。实际上有两个问题
频道和wg的大小应为3
我应该将wg作为指针传递
更新了代码
package main
import (
"fmt"
"sync"
)
func main() {
c := make(chan int, 3)
var wg sync.WaitGroup
wg.Add(3)
go doSomething(c, &wg)
go doSomething(c, &wg)
go doSomething(c, &wg)
wg.Wait()
close(c)
for v := range c {
fmt.Print(v)
}
}
func doSomething(c chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
c <- 1
}
答案 2 :(得分:0)
是的,代码中有一个重要的 问题 。
您致电go doSomething(c, wg)
只需传递wg
值即可。
你应该知道
Go中的参数始终按值传递。当一个时使用指针 参数可以修改。
所以你应该这样做go doSomething(c, &wg)
,wg
函数中的main
将由defer wg.Done()
中的func doSomething(c chan<- int, wg sync.WaitGroup)
修改。
。