2017-09-09 14 views
0

私のアプリを並列化するために私はthis postに従っています。私は完全にラインcase out <- n * n:を理解していないgo中チャンネルの範囲を選択

func sq(done <-chan struct{}, in <-chan int) <-chan int { 
    out := make(chan int) 
    go func() { 
     defer close(out) 
     for n := range in { 
      select { 
      case out <- n * n: 
      case <-done: 
       return 
      } 
     } 
    }() 
    return out 
} 

:私はこのコードを調整する必要があります。 nの値がある場合は、それを四角形にしてチャンネルに送りますが、それはなぜわかりません。 selectちょうど最初にtrueケースを取るか?それは書き換えることができます

for n := range in { 
    select { 
    case n: 
     out <- n * n 
    case <-done: 
     return 
    } 
} 

はとにかく、私は、関数呼び出しでラインcase out <- n * n:を交換する必要があります。私は次のように変更しました:それはこのようになります

out := make(chan structs.Ticket) 

go func() { 
    defer close(out) 
    for url := range inputChannel { 
     select { 
     case url: 
      data, err := GetData(url) 
      fmt.Println("Got error: ", err) 
      out <- data 
     case <-done: 
      return 
     } 
    } 
}() 

return out 

がコンパイルされます(私はまだそれをコンパイルすることはできません)、それは、並列コードをデバッグするのは簡単ではありませんので、私はcase urlを使用していたことを確認したかったですrangeでチャンネルを選択するには正しい方法です。これは正しいですか?

更新

私は私のコードで、残りの問題を削除した、と今私がコンパイルしようとすると、私はエラーメッセージを取得OK:

url evaluated but not used 
select case must be receive, send or assign recv 
+1

私はあなたが 'select'と' switch'ステートメントを混同していると思います。 'select'ケースはチャネル操作にのみ関係します – JimB

答えて

0
  1. いいえ、selectは、それがすべてで式を取ることはありません...最初の真の表現を負いません。式のケースとして現れることができるのは、チャネル送信、チャネル受信、およびチャネル受信の割り当てが右側にあることだけです。

    select { 
    case out <- n * n: 
    case <-done: 
        return 
    } 
    

outに送信が可能な場合」と言う(すなわち、それは容量やアクティブな読者を残りました)、それに価値n * nを送信し続ける。doneから受信することが可能である場合は、からの復帰どちらも可能な場合は、どちらかが可能になるまで待ちます。 (仕様のSelect Statementsを参照)。

送信したい値を計算する必要があります(チャネルの右側に置くには複雑すぎます)。selectの前に入力してください。この仕様では、selectのsend文の式はすべて前もって計算されるため、何も失われないことが明らかになりました。

+0

あなたはselectの前に値を計算すると言っていますが、私の 'GetData'関数は数分で完了します。 'done'に何かがある場合、私はすぐに戻りたいです。 'range'の後に' GetData'を呼び出すと、 'done'が読む準備ができていてもその高価な関数が実行されます。 'out'が書き込みを受け入れることができる場合にのみ' GetData'を実行する代替手段がありますか? – jbrown

0

私はしないでください行case out <- n * nを完全に理解してください:。私は、nの値があればそれを四角形にしてチャンネルに送りますが、なぜそれが分からないのか分かりません。

これは間違っています。 case out <- n * nは、outが読む準備ができているかどうかを確認し、がある場合はn * noutに送信します。 doneも準備ができていない限り。

selectは、複数のチャットチャンネルがある場合に使用されます。どちらのチャンネルも準備が整っていれば、そのようになります。複数のチャンネルが準備できている場合は、ランダムに1つを選択します。

select { 
    case out <- n * n: 
    case <-done: 
     return 
    } 
} 

これはoutdone上で選択されます。いずれかが進行する準備ができている場合、つまりoutは読む準備ができているか、doneから何かが読み込まれている場合は、その1つを選択します。注文はランダムですので、から何かが読み込まれていても、より多くのメッセージをoutに送信することは可能です。

このパターンは、無限のゴルーチンをシャットダウンするために使用されます。出力チャンネルからの読み込みを停止すると、それ以上の処理は行われませんが、メモリ内で停止します。だから、doneに値を渡すことで、ゴルーチンにシャットダウンを伝えることができます。


UPDATE:ゴルーチン入力チャンネルをループし、出力を送信している元の場合には、doneが不要な合併症です。入力チャンネルが閉じられると、機能が戻ります。

func sq(in <-chan int) <-chan int { 
    out := make(chan int) 
    go func() { 
     defer close(out) 
     for n := range in { 
      out <- n * n 
     } 
    }() 
    return out 
} 

func main() { 
    in := make(chan int) 
    out := sq(in) 
    for _,i := range []int{1,2,3,4} { 
     in <- i 
     fmt.Println(<-out) 
    } 

    // The `range` inside the goroutine from sq() will exit, 
    // and the goroutine will return. 
    close(in) 
} 

それだけで正方形の増え続けるセットを吐き出した場合、doneが無限ループ内で必要であろう。 rangeかをここでやっていることselect上の影響はありませんにいる

func sq(done chan bool) <-chan int { 
    out := make(chan int) 
    go func() { 
     defer close(out) 
     n := 0 
     for { 
      select { 
       case <-done: 
        return 
       case out<-n*n: 
        n++ 
      } 
     } 
    }() 
    return out 
} 

func main() { 
    done := make(chan bool) 
    out := sq(done) 
    for range []int{1,2,3,4} { 
     fmt.Println(<-out) 
    } 

    // The switch in the goroutine will be able to read 
    // from done (out's buffer being already full) and return. 
    done <- true 
} 
+0

私はこのパターンをより複雑なパイプラインに適用しています。リンクされたブログ記事を読んだら、 'done'チャンネルを使ってエラー時にパイプライン全体を取り消すことができます。私は実際に正方形を計算しているわけではありません。 – jbrown

+0

@jbrown入力チャンネルをループするだけであれば、入力チャンネルを閉じてエラーが発生したときにgoroutineを簡単に閉じることができます。 – Schwern

+0

これはファンアウト/ファンインパイプラインの一部であり、ポストによればそれほど単純ではありません。しかし、それを私が実装したのは初めてのことなので、もっとシンプルかもしれません。 – jbrown