2017-01-14 10 views
1

ある私はゴルーチンとチャネルすべてのゴルーチンが眠ってデッドロック

package main 

import (
    "fmt" 
    "math/rand" 
    "time" 
) 

func boring(msg string) <-chan string { 
    c := make(chan string) 
    go func() { 
     for i := 0; ; i++ { 
      c <- fmt.Sprintf("%s %d", msg, i) 
      time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond) 
     } 
    }() 
    return c 
} 
func main() { 
    c := fanInNew(boring("joe"), boring("anh")) 
    for i := 0; i < 10; i++ { 
     fmt.Println(<-c) 
    } 
    fmt.Println("You both are boring, I am leaving") 
} 

func fanInNew(input1, input2 <-chan string) <-chan string { 
    c := make(chan string) 
    for { 
     select { 
     case s := <-input1: 
      c <- s 
     case s := <-input2: 
      c <- s 
     } 
    } 
    return c 
} 

で遊んしようとしています、私はそれは私にエラーを与えているこのプログラムを実行すると、すべてのゴルーチンは、デッドロック眠っています。

しかし、selectを匿名のgoroutineに入れてもうまく動作します。実施例:

package main 

import (
    "fmt" 
    "math/rand" 
    "time" 
) 

func boring(msg string) <-chan string { 
    c := make(chan string) 
    go func() { 
     for i := 0; ; i++ { 
      c <- fmt.Sprintf("%s %d", msg, i) 
      time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond) 
     } 
    }() 
    return c 
} 
func main() { 
    c := fanInNew(boring("joe"), boring("anh")) 
    for i := 0; i < 10; i++ { 
     fmt.Println(<-c) 
    } 
    fmt.Println("You both are boring, I am leaving") 
} 

func fanInNew(input1, input2 <-chan string) <-chan string { 
    c := make(chan string) 
    go func() { 
     for { 
      select { 
      case s := <-input1: 
       c <- s 
      case s := <-input2: 
       c <- s 
      } 
     } 
    }() 
    return c 
} 

あなたはそれの背後にある推論を理解するのを手伝ってもらえますか?

答えて

2

for文は永遠にループし、そのため<-cちゃんが渡されることはありませんし、ちゃんずは満たされますが、mainスレッドがc := fanInNew(a, b)を待って立ち往生。

fanInNew()は(ところでselect上とブロック)永遠forためのループを返すことはありません:メインスレッドで次に

func fanInNew(input1, input2 <-chan string) <-chan string { 
    c := make(chan string) 
    for { // Loop forever and read from inputs 1 and 2 
     select { 
     case s := <-input1: 
      c <- s 
     case s := <-input2: 
      c <- s    
     } 
    } 
    return c 
} 

この機能cちゃんを返すことはありません。

func main() { 
    // Never gets passed the next line 
    c := fanInNew(boring("joe"), boring("anh")) 
} 

だからあなたはあなたが第二の例で行ったようforは、ゴルーチンで自分自身をループ置くことができます。 通常、メッセージは(close()などで)渡すか、return文に達するため、goroutinesは返すべきです。

いずれの場合でも、第2の例では、匿名の使用を示すのに最適ですクロージャ。ゴルーチンに渡さchanは、他の場所で返され、スレッド間を通過する安全なメッセージを有効にすることができます。

c := make(chan string) 
go func() { 
    for { 
     select { 
     case s := <-input1: 
      c <- s 
     case s := <-input2: 
      c <- s 
     } 
    } 
}() 
return c 

chan上の選択など、匿名のゴルーチンにforループを終了させるいくつかの方法があります、クロージングチャンネルclose()を返すことができます。また、一般的にWaitGroupsを達成することができます。

+0

その後、私はgoroutinesに入れたときに 'for'ループをどのように返しますか? ?ありがとう – sks

+0

もう一つの 'chan'と空のstruct、closingチャンネルを渡すことができます。しかし、 'WaitGroups'もうまく動作します – Nevermore

+0

あなたを持って..thanks :) – sks

関連する問題