我正在尝试Golang中的频道概念。我编写了以下程序playground,以使用通道实现计数器。但是,尽管我正在goroutine主体中进行一些打印,但是我没有得到任何输出。
func main() {
wg := sync.WaitGroup{}
ch := make(chan int)
count := func(ch chan int) {
var last int
last = <-ch
last = last + 1
fmt.Println(last)
ch <- last
wg.Done()
}
wg.Add(10)
for i := 1; i <= 10; i++ {
go count(ch)
}
}
我希望至少有一些输出,但是我什么都没得到。
答案 0 :(得分:8)
当main()
函数(main
goroutine)结束时,您的程序也结束了(它不等待其他非main
goroutine完成)。您必须在末尾添加一个wg.Wait()
调用。参见No output from goroutine in Go。
一旦这样做,就会陷入僵局。这是因为所有goroutine都从尝试从通道接收值开始,然后才发送东西。
因此,您应该首先在通道上发送一些内容,以使至少一个goroutine继续进行。
执行此操作后,您将看到打印10次的数字,并再次出现死锁。这是因为当最后一个goroutine尝试发送其递增编号时,将没有人接收到该编号。一种简单的解决方法是为通道提供缓冲区。
最终的工作示例:
wg := sync.WaitGroup{}
ch := make(chan int, 2)
count := func(ch chan int) {
var last int
last = <-ch
last = last + 1
fmt.Println(last)
ch <- last
wg.Done()
}
wg.Add(10)
for i := 1; i <= 10; i++ {
go count(ch)
}
go func() {
ch <- 0
}()
wg.Wait()
输出(在Go Playground上尝试):
1
2
3
4
5
6
7
8
9
10
还要注意,由于我们缓冲了通道,因此不必使用其他goroutine发送初始值,我们可以在main
goroutine中进行此操作:
ch <- 0
wg.Wait()
这将输出相同的内容。在Go Playground上尝试一下。
答案 1 :(得分:1)
func main() {
wg := sync.WaitGroup{}
ch := make(chan int)
count := func(ch chan int) {
var last int
last, ok := <-ch // 这里做一层保护
if !ok {
return
}
last = last + 1
fmt.Println(last)
go func(ch chan int, res int) {
ch <- res
}(ch, last)
wg.Done()
}
go func() {
ch <- 0
}()
wg.Add(10)
for i := 1; i <= 10; i++ {
go count(ch)
}
wg.Wait()
fmt.Println("main finish")
close(ch)
}