2015-08-05 5 views
2

Краткая программа о select заявление для каналов.Go select statement

package main 

import "fmt" 

func fibonacci(c, quit chan int) { 
    x, y := 0, 1 
    for { 
     select { 
     case c <- x: 
      x, y = y, x+y 
     case s := <-quit: 
      fmt.Println("quit =",s) 
      return 
     } 
    } 
} 

func main() { 
    c := make(chan int) 
    quit := make(chan int) 
    go func() { 
     for i := 0; i < 10; i++ { 
      fmt.Println(<-c) 
     } 
     quit <- 9 
    }() 
    fibonacci(c, quit) 
} 

В результате приведенного выше кода:

0 
1 
1 
2 
3 
5 
8 
13 
21 
34 
quit = 9 

Он работал отлично. Но после того, как я изменил (в func fibonacci)

case s := <-quit: 
    fmt.Println("quit =",s) 

в

case <-quit: 
    fmt.Println(<-quit) 

произошла фатальная ошибка:

0 
1 
1 
2 
3 
5 
8 
13 
21 
34 
fatal error: all goroutines are asleep - deadlock! 

goroutine 1 [chan receive]: 
main.fibonacci(0x18348040, 0x18348080) 
    /tmp/compile42.go:12 +0xf9 
main.main() 
    /tmp/compile42.go:27 +0x11c 

Где ошибка взялось?

ответ

7

Во втором случае вы получаете значение формы канала два раза. Каждый раз, когда вы делаете что-то вроде < -channel, вы выталкиваете одно значение из канала.

Поэтому программа ожидает на неопределенный срок на линии

fmt.Println(<-quit) 

, но к счастью, идут достаточно умны, чтобы обнаружить эту ситуацию и панику с ошибкой «все goroutines усопших - ТУПИК»

3

Линия

fmt.Println(<-quit) 

ожидает очередного значения на канале, который никогда не появится в соответствии с кодом, который у вас есть.

Вы должны иметь в виду, прежде чем линия в избранных:

case s := <-quit 

уже удалили бросить значение из канала.

Таким образом, он никогда не будет завершен.