2016-03-31 55 views
0

"Eat""Work""Sleep"をそれぞれ3番目、8番目、24番目の秒ごとに出力するプログラムを作成しようとしています。ここに私のコードは次のとおりです。Golang:select文が終了しないときに終了する

package main 

import (
"fmt" 
"time" 
) 

func Remind(text string, delay time.Duration) <-chan string { //channel only for receiving strings 
    ch := make(chan string) // buffered/unbuffered? 
    go func() { 
     for { 
      msg := "The time is " + time.Now().Format("2006-01-02 15:04:05 ") + text 
      ch <- msg 
      time.Sleep(delay) // waits according to specification 
     } 
    }() 
    return ch 
} 

func main() { 
    ch1 := Remind("Eat", 1000*1000*1000*3) // every third second  
    ch2 := Remind("Work", 1000*1000*1000*8) // every eighth second 
    ch3 := Remind("Sleep", 1000*1000*1000*24) // every 24th second 
    select { // chooses one channel that is not empty. Should run forever (?) 
     case rem1 := <-ch1: 
      fmt.Println(rem1) 
     case rem2 := <-ch2: 
      fmt.Println(rem2) 
     case rem3 := <-ch3: 
      fmt.Println(rem3) 
    } 
} 

それに伴う問題は、それが"Eat"が続く時間を印刷した後、すぐに実行を停止していることです。私が読んだ他の例では、selectの声明は永遠に続きます。なぜそれは今ではないのですか?

答えて

2

selectがどこまで続くのか分かりませんが、それはありません。

caseが実行されると、select文は「完了」となります。 caseで指定された通信操作のどれものいずれも実行できない場合は、defaultブランチはありません。selectはブロックされます。オプスが進むことができます。しかし、caseが実行されると、selectは繰り返されません。

仕様:Select statementsから該当するセクションをお読みください。

それが永遠に繰り返させるために無限のforに置く:追記として

for { 
    select { // chooses one channel that is not empty. Should run forever (?) 
    case rem1 := <-ch1: 
     fmt.Println(rem1) 
    case rem2 := <-ch2: 
     fmt.Println(rem2) 
    case rem3 := <-ch3: 
     fmt.Println(rem3) 
    } 
} 

を:

あなたはtimeパッケージからの定数を使用して、time.Duration値はるかに簡単に作成できます。

ch1 := Remind("Eat", 3*time.Second) // every third second 
ch2 := Remind("Work", 8*time.Second) // every eighth second 
ch3 := Remind("Sleep", 24*time.Second) // every 24th second 

あなたのRemind()機能に似たタスク用のタイプです。

+0

は、何かを誤解している必要があります。ありがとう! – Sahand

+0

@Sandiほとんどの場合、 'select'は、通信操作が必要であれば永遠に進むことができないかどうかを待つでしょう。しかしそれは繰り返されません。 – icza

+0

例えば、すべてのチャンネルが空であれば、 'select'は待機しますか? – Sahand

2

selectは、ほとんどがスイッチ制御文に似ており、通信スイッチとも呼ばれます。 selectはチャネルの受信データをリッスンしますが、チャネルに値が送信される場合もあります。ある単語では、同時に実行するgoroutineの値を取得または送信するためにselectが使用されます。

メインのゴルーチンで現在の時刻を実行しているため、この例では常に実行されます。しかし、他のゴルーチンはselect文で実行されるので、実行されるチャンスは必ずしも得られません。なぜなら、一度caseがチャネルブロックを実行するからです。

何を選択することはありません:

  • すべてがブロックされている場合は、複数のは、それがランダムに1つを選択し、続行することができます場合は、1つは
  • を続行できるようになるまで、それは待ちます。
  • チャネル操作が実行できず、default句が存在する場合は、が実行されます。デフォルトは常に実行可能です(実行準備が整っています)。

デフォルトの大文字小文字のselect文でsendオペレーションを使用すると、sendが非ブロックになることが保証されます。

は永遠に実行ループのためにそれを使用するには、次の

package main 

import (
"fmt" 
"time" 
) 

func Remind(text string, delay time.Duration) <-chan string { //channel only for receiving strings 
    ch := make(chan string) // buffered/unbuffered? 
    go func() { 
     for { 
      msg := "The time is " + time.Now().Format("2006-01-02 15:04:05 ") + text 
      ch <- msg 
      time.Sleep(delay) // waits according to specification 
     } 
    }() 
    return ch 
} 

func main() { 
    ch1 := Remind("Eat", 1000*1000*1000*3) // every third second  
    ch2 := Remind("Work", 1000*1000*1000*8) // every eighth second 
    ch3 := Remind("Sleep", 1000*1000*1000*24) // every 24th second 
    for { 
     select { // chooses one channel that is not empty. Should run forever (?) 
     case rem1 := <-ch1: 
      fmt.Println(rem1) 
     case rem2 := <-ch2: 
      fmt.Println(rem2) 
     case rem3 := <-ch3: 
      fmt.Println(rem3) 
     } 
    } 
} 

http://play.golang.org/p/BuPqm3xsv6

+0

答えをありがとう。チャンネルがブロックされているとはどういう意味ですか?私はその定義を見つけるのが難しいです。 – Sahand

+0

編集した回答を見る –

関連する問題