2016-08-08 4 views
2

Рассмотрим следующий go playgroundТупик, когда нерест goroutine в цикле

package main 

import "fmt" 

func main() { 

    var chan_array [2]chan int 

    chan1 := make(chan int) 
    chan2 := make(chan int) 

    chan_array[0] = chan1 
    chan_array[1] = chan2 


    for i := 0; i < 2; i++ { 
     go func() { 

      select { 
       case x := <- chan_array[i]: 
        if (x == 0) { 
         return 
        }  
        fmt.Println(x) 
      } 
     }() 
    } 

    chan1<- 1 
    chan2<- 2 
    chan1<- 0 
    chan2<- 0 
} 

Код выше пытается создать 2 работающих goroutines с этим прослушивает канал для сигнализации печати или близко.

Но приведенный выше код работает в мертвой блокировке.

Я точно не знаю, почему

Может кто-то указать на мою ошибку?

Благодаря

+0

Возможный дубликат [? Почему Golang ручка закрытия по-разному в goroutines] (http://stackoverflow.com/questions/25919213/why-does-golang-handle-closures -differently-in-goroutines) –

ответ

4

Есть некоторые проблемы:
Что такое значение i когда chan_array[i-1] работает:

for i := 0; i < 2; i++ { 
    go func() { 
     select { 
     case x := <- chan_array[i-1]: 
      if x == 0 { 
       return 
      } 
      fmt.Println(x) 
     } 
    }() 
} 

попробовать это:

for i := 0; i < 2; i++ { 
    go func(i int) { 
     select { 
     case x := <-chan_array[i]: 
      if x == 0 { 
       return 
      } 
      fmt.Println(x) 
     } 
    }(i) 
} 

Давайте упростить код (с некоторыми поправками):

package main 

import "fmt" 

func main() { 
    chan1 := make(chan int) 
    chan2 := make(chan int) 

    go routine(chan1) 
    go routine(chan2) 

    chan1 <- 1 
    chan2 <- 2 
    chan1 <- 0 
    chan2 <- 0 
} 

func routine(ch chan int) { 
    select { 
    case x := <-ch: 
     if x == 0 { 
      return 
     } 
     fmt.Println(x) 
    } 
} 

С этим:

chan1 <- 1 
chan2 <- 2 

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

all goroutines are asleep - deadlock! 

ваши goroutines закончена и нет goroutines прослушивания в chan1 и chan1 здесь:

chan1 <- 0 
chan2 <- 0 

исправленный работает пример кода :

package main 

import "fmt" 

func main() { 
    chan1 := make(chan int) 
    chan2 := make(chan int) 

    go routine(chan1) 
    go routine(chan2) 

    chan1 <- 1 
    chan2 <- 2 
    chan1 <- 0 
    chan2 <- 0 
} 

func routine(ch chan int) { 
    for { 
     select { 
     case x := <-ch: 
      if x == 0 { 
       return 
      } 
      fmt.Println(x) 
     } 
    } 
} 

выход:

1 
2 
1

К тому времени, goroutines работающих под управлением переменной i уже увеличивается. Передайте его как параметр функции.

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

+0

Я попытался добавить параметр, но я испытываю [dead lock] (https://play.golang.org/p/SxcnORT6Ru). – user3591466

+0

@ user3591466: Ну, есть еще одна проблема. Вы отправляете на каналы дважды, но ваши goroutines выходят после получения одного значения. –