尝试使用 'range' 打印通道值后出现死锁
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)
}
//fatal error: all goroutines are asleep - deadlock!
fmt.Println("Done")
}
这导致:
1
3
6
fatal error: all goroutines are asleep - deadlock!
而且我不明白是什么导致了这个错误。我的理解是,在我的函数 sum_up
中,我正在向 my_channel
添加新值。为什么我尝试打印值后出现问题?由于我看到 1、3、6 被打印出来,这意味着所有 goroutines
都已成功完成。
此外,如果尝试打印通道值的块
for ele := range my_channel {
fmt.Println(ele)
}
被删除了,那我就不会报错了。所以它包括导致错误的块,但为什么呢?
当您在通道上使用 range
时,它将永远等待值或直到通道关闭。这是死锁,因为当最后一个值写入 my_channel 时,它将永远等待一个永远不会到来的值。
这里有一个稍微修改过的变体,展示了如何完全离开范围:https://play.golang.org/p/YDlM8EcRnx
for range chan
当chan收到关闭信号时退出。您必须 close(my_channel)
某处,否则循环将永远等待。
空通道上的 for-range 将阻塞,直到有要从通道读取的元素或直到通道关闭。
这是一个使用 sync.WaitGroup
来说明有多少 goroutines 保持活动状态的版本。所有 goroutines 完成后,通道关闭,for-range 循环存在。
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")
}
这是我在 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")
}
这导致:
1
3
6
fatal error: all goroutines are asleep - deadlock!
而且我不明白是什么导致了这个错误。我的理解是,在我的函数 sum_up
中,我正在向 my_channel
添加新值。为什么我尝试打印值后出现问题?由于我看到 1、3、6 被打印出来,这意味着所有 goroutines
都已成功完成。
此外,如果尝试打印通道值的块
for ele := range my_channel {
fmt.Println(ele)
}
被删除了,那我就不会报错了。所以它包括导致错误的块,但为什么呢?
当您在通道上使用 range
时,它将永远等待值或直到通道关闭。这是死锁,因为当最后一个值写入 my_channel 时,它将永远等待一个永远不会到来的值。
这里有一个稍微修改过的变体,展示了如何完全离开范围:https://play.golang.org/p/YDlM8EcRnx
for range chan
当chan收到关闭信号时退出。您必须 close(my_channel)
某处,否则循环将永远等待。
空通道上的 for-range 将阻塞,直到有要从通道读取的元素或直到通道关闭。
这是一个使用 sync.WaitGroup
来说明有多少 goroutines 保持活动状态的版本。所有 goroutines 完成后,通道关闭,for-range 循环存在。
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")
}