英文:
Deadlock after attempting to print values of channel using 'range'
问题
这是我在Go Playground上的代码:
package main
import (
"fmt"
)
func sum_up(my_int int, cs chan int) {
my_sum := 0
for i := 0; i < my_int; i++ {
my_sum += i
}
cs <- my_sum
}
func main() {
my_channel := make(chan int)
for i := 2; i < 5; i++ {
go sum_up(i, my_channel)
}
for ele := range my_channel {
fmt.Println(ele)
}
fmt.Println("Done")
}
运行结果为:
1
3
6
fatal error: all goroutines are asleep - deadlock!
我不明白是什么导致了这个错误。我理解的是,在我的函数sum_up
中,我正在向my_channel
添加新的值。为什么在尝试打印这些值之后出现问题?因为我看到1、3、6被打印出来,这意味着所有的goroutine
都已经成功完成。
此外,如果移除尝试打印通道值的代码块:
for ele := range my_channel {
fmt.Println(ele)
}
那么我就不会得到错误。所以问题出在导致错误的代码块中,但是为什么呢?
英文:
Here is my code at Go Playground
package main
import (
"fmt"
)
func sum_up(my_int int, cs chan int) {
my_sum := 0
for i := 0; i < my_int; i++ {
my_sum += i
}
cs <- my_sum
}
func main() {
my_channel := make(chan int)
for i := 2; i < 5; i++ {
go sum_up(i, my_channel)
}
for ele := range my_channel {
fmt.Println(ele)
}
//fatal error: all goroutines are asleep - deadlock!
fmt.Println("Done")
}
Which results in:
1
3
6
fatal error: all goroutines are asleep - deadlock!
And I don't understand what causes the error. My understanding is that in my function sum_up
I am adding new values to my_channel
. Why does the problem occur after I try to print out the values? Since I see 1,3,6 are printed it means that all goroutines
have successfully finished.
Moreover, if the block that attempts to print the values of the channel
for ele := range my_channel {
fmt.Println(ele)
}
Is removed, then I don't get the error. So it is including the block that causes the error, but why?
答案1
得分: 3
一个空通道上的for-range循环将会阻塞,直到从通道中读取到元素或者通道被关闭。
这里是一个使用sync.WaitGroup
的版本,用于记录还有多少个goroutine处于活动状态。当所有的goroutine都完成后,通道会被关闭,for-range循环退出。
package main
import (
"fmt"
"sync"
)
func sum_up(my_int int, cs chan int, wg *sync.WaitGroup) {
my_sum := 0
for i := 0; i < my_int; i++ {
my_sum += i
}
cs <- my_sum
wg.Done()
}
func main() {
wg := &sync.WaitGroup{}
my_channel := make(chan int)
for i := 2; i < 5; i++ {
wg.Add(1)
go sum_up(i, my_channel, wg)
}
// 运行一个goroutine来监视有多少个sum_up正在运行。
go func(cs chan int, wg *sync.WaitGroup) {
wg.Wait()
close(cs)
}(my_channel, wg)
for ele := range my_channel {
fmt.Println(ele)
}
// fatal error: all goroutines are asleep - deadlock!
fmt.Println("Done")
}
链接:https://play.golang.org/p/ZnLYxLMNdF
英文:
A for-range on a empty channel will block until there are elements to read from the channel or until the channel is closed.
Here is a version that uses sync.WaitGroup
to account for how many goroutines remain active. After all goroutines have finished, the channel is closed and the for-range loop exists.
https://play.golang.org/p/ZnLYxLMNdF
package main
import (
"fmt"
"sync"
)
func sum_up(my_int int, cs chan int, wg *sync.WaitGroup) {
my_sum := 0
for i := 0; i < my_int; i++ {
my_sum += i
}
cs <- my_sum
wg.Done()
}
func main() {
wg := &sync.WaitGroup{}
my_channel := make(chan int)
for i := 2; i < 5; i++ {
wg.Add(1)
go sum_up(i, my_channel, wg)
}
// Run a goroutine that will monitor how many sum_up are running.
go func(cs chan int, wg *sync.WaitGroup) {
wg.Wait()
close(cs)
}(my_channel, wg)
for ele := range my_channel {
fmt.Println(ele)
}
//fatal error: all goroutines are asleep - deadlock!
fmt.Println("Done")
}
答案2
得分: 2
当你在通道上使用range
时,它会无限期地等待值,直到通道关闭。这会导致死锁,因为当最后一个值被写入my_channel
时,它将永远等待一个永远不会到来的值。
这里有一个稍微修改过的变体,展示了如何干净地退出range
循环:https://play.golang.org/p/YDlM8EcRnx
英文:
When you use range
on a channel, it will wait for values forever or until the channel is closed. It's deadlocking because when the last value is written to my_channel, it will wait forever for a value that will never come.
Here's a slightly modified variant that shows how to cleanly leave the range: https://play.golang.org/p/YDlM8EcRnx
答案3
得分: 0
for range chan
在接收到关闭信号时退出。你必须在某个地方使用 close(my_channel)
,否则循环将一直等待。
英文:
for range chan
exit when chan receive close signal. You must close(my_channel)
somewhere, or loop will wait forever.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论