Go中缓冲通道的死锁
Deadlocks with buffered channels in Go
我遇到以下代码fatal error: all goroutines are asleep - deadlock!
我使用缓冲通道是否正确?如果你能给我指点,我将不胜感激。不幸的是,我已经无计可施了。
func main() {
valueChannel := make(chan int, 2)
defer close(valueChannel)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go doNothing(&wg, valueChannel)
}
for {
v, ok := <- valueChannel
if !ok {
break
}
fmt.Println(v)
}
wg.Wait()
}
func doNothing(wg *sync.WaitGroup, numChan chan int) {
defer wg.Done()
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
numChan <- 12
}
主 goroutine 在收到所有值后阻塞 <- valueChannel
。关闭通道以解锁主 goroutine。
func main() {
valueChannel := make(chan int, 2)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go doNothing(&wg, valueChannel)
}
// Close channel after goroutines complete.
go func() {
wg.Wait()
close(valueChannel)
}()
// Receive values until channel is closed.
// The for / range loop here does the same
// thing as the for loop in the question.
for v := range valueChannel {
fmt.Println(v)
}
}
Run the example on the playground.
上面的代码独立于 goroutines 发送的值的数量。
如果 main()
函数可以确定 goroutine 发送的值的数量,则从 main()
:
接收该数量的值
func main() {
const n = 10
valueChannel := make(chan int, 2)
for i := 0; i < n; i++ {
go doNothing(valueChannel)
}
// Each call to doNothing sends one value. Receive
// one value for each call to doNothing.
for i := 0; i < n; i++ {
fmt.Println(<-valueChannel)
}
}
func doNothing(numChan chan int) {
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
numChan <- 12
}
主要问题出在频道接收的for循环上。
逗号 ok 习语在通道上略有不同,ok 表示接收到的值是在通道上发送的 (true) 还是因为通道关闭且为空而返回的零值 (false)。
在这种情况下,通道正在等待发送数据,因为它已经完成十次发送值:Deadlock。
因此,除了代码设计之外,如果我只需要在这里做尽可能少的更改,那就是:
func main() {
valueChannel := make(chan int, 2)
defer close(valueChannel)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go doNothing(&wg, valueChannel)
}
for i := 0; i < 10; i++ {
v := <- valueChannel
fmt.Println(v)
}
wg.Wait()
}
func doNothing(wg *sync.WaitGroup, numChan chan int) {
defer wg.Done()
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
numChan <- 12
}
我遇到以下代码fatal error: all goroutines are asleep - deadlock!
我使用缓冲通道是否正确?如果你能给我指点,我将不胜感激。不幸的是,我已经无计可施了。
func main() {
valueChannel := make(chan int, 2)
defer close(valueChannel)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go doNothing(&wg, valueChannel)
}
for {
v, ok := <- valueChannel
if !ok {
break
}
fmt.Println(v)
}
wg.Wait()
}
func doNothing(wg *sync.WaitGroup, numChan chan int) {
defer wg.Done()
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
numChan <- 12
}
主 goroutine 在收到所有值后阻塞 <- valueChannel
。关闭通道以解锁主 goroutine。
func main() {
valueChannel := make(chan int, 2)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go doNothing(&wg, valueChannel)
}
// Close channel after goroutines complete.
go func() {
wg.Wait()
close(valueChannel)
}()
// Receive values until channel is closed.
// The for / range loop here does the same
// thing as the for loop in the question.
for v := range valueChannel {
fmt.Println(v)
}
}
Run the example on the playground.
上面的代码独立于 goroutines 发送的值的数量。
如果 main()
函数可以确定 goroutine 发送的值的数量,则从 main()
:
func main() {
const n = 10
valueChannel := make(chan int, 2)
for i := 0; i < n; i++ {
go doNothing(valueChannel)
}
// Each call to doNothing sends one value. Receive
// one value for each call to doNothing.
for i := 0; i < n; i++ {
fmt.Println(<-valueChannel)
}
}
func doNothing(numChan chan int) {
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
numChan <- 12
}
主要问题出在频道接收的for循环上。 逗号 ok 习语在通道上略有不同,ok 表示接收到的值是在通道上发送的 (true) 还是因为通道关闭且为空而返回的零值 (false)。 在这种情况下,通道正在等待发送数据,因为它已经完成十次发送值:Deadlock。 因此,除了代码设计之外,如果我只需要在这里做尽可能少的更改,那就是:
func main() {
valueChannel := make(chan int, 2)
defer close(valueChannel)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go doNothing(&wg, valueChannel)
}
for i := 0; i < 10; i++ {
v := <- valueChannel
fmt.Println(v)
}
wg.Wait()
}
func doNothing(wg *sync.WaitGroup, numChan chan int) {
defer wg.Done()
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
numChan <- 12
}