2017-04-08 43 views
1

我是Go的新手。當我註釋掉第二個例程時,有一個致命的錯誤。我不明白是什麼原因導致這個錯誤發生。你能解釋給我嗎?goroutines之間的死鎖

package main 

import (
    "fmt" 
    "time" 
) 

func main() { 
    ch := make(chan int) 
    go func() { 
     for i := 0; i < 10; i++ { 
      ch <- i 
     } 
    }() 
    // go func() { 
     for { 
      if num, ok := <-ch; !ok { 
       break 
      } else { 
       fmt.Printf("%d\n", num) 
      } 
     } 
    // }() 
    time.Sleep(2 * time.Second) 
    close(ch) 
} 

這將打印以下代碼:

0 
1 
2 
3 
4 
5 
6 
7 
8 
9 
fatal error: all goroutines are asleep - deadlock! 

goroutine 1 [chan receive]: 
main.main() 
    /tmp/sandbox169127128/main.go:17 +0xa0 

Program exited. 

回答

5

ch接收從發送接收夠程的所有值後的接收for循環塊。運行時檢測到程序卡住併發生混亂。

的解決方法是將所有的值後,關閉信道:

go func() { 
    for i := 0; i < 10; i++ { 
     ch <- i 
    } 
    close(ch) 
}() 

接收關於所述封閉通道產生的值0, false。接收for循環會打破假值。從程序結束刪除close(ch)

Run it on the playground

+0

謝謝你的簡潔解釋,櫻桃色。我不確定我完全理解「阻止」的想法。 這是否意味着接收循環卡住永久等待?這是因爲下面的代碼左邊的ok表示接收真,但永遠不會有另一個num給? if num,ok:= <-ch; !ok – Pizzas

+0

@Pizzas:https://en.wikipedia.org/wiki/Blocking_(computing)在你的情況下,'num,ok:= <-ch'被阻塞(等待另一個響應)。其他響應永遠不會出現,因爲發送程序已經退出。如果在發送去程序中關閉通道,則接收另一個響應(表示通道關閉)。 – Flimzy

+0

@Pizzas在一個開放頻道上接收等待一個值被髮送到頻道。在接收到發送goroutine的所有值後,接收循環會一直等待。 –

2

因爲在第一個goroutine退出前你沒有關閉通道。下面的代碼應該可以工作。

package main 

import (
    "fmt" 
    "time" 
) 

func main() { 
    ch := make(chan int) 
    go func() { 
     for i := 0; i < 10; i++ { 
      ch <- i 
     } 
     close(ch) 
    }() 
    //go func() { 
     for { 
      if num, ok := <-ch; !ok { 
       break 
      } else { 
       fmt.Printf("%d\n", num) 
      } 
     } 
    //}() 
    time.Sleep(2 * time.Second) 
} 

嘗試一下這裏:https://play.golang.org/p/OdxNqbaZmj